mirror of
https://github.com/lightningnetwork/lnd.git
synced 2025-10-03 19:34:23 +02:00
input: switch to using new txscript.ScriptTemplate function
In this commit, we switch to using the new txscript.ScriptTemplate function. This allows us to write the script in plain text, using some hidden template operations to swap in items like keys or sigs. This reduces in less code and boiler plate over all, the code that defines the script now reads as if it was a comment.
This commit is contained in:
@@ -20,6 +20,10 @@ import (
|
||||
"golang.org/x/crypto/ripemd160"
|
||||
)
|
||||
|
||||
// TemplateParams is a type alias for the map[string]interface{} type used
|
||||
// with txscript.ScriptTemplate to make code more readable.
|
||||
type TemplateParams map[string]interface{}
|
||||
|
||||
var (
|
||||
// TODO(roasbeef): remove these and use the one's defined in txscript
|
||||
// within testnet-L.
|
||||
@@ -83,69 +87,62 @@ func ParseSignature(rawSig []byte) (Signature, error) {
|
||||
// WitnessScriptHash generates a pay-to-witness-script-hash public key script
|
||||
// paying to a version 0 witness program paying to the passed redeem script.
|
||||
func WitnessScriptHash(witnessScript []byte) ([]byte, error) {
|
||||
bldr := txscript.NewScriptBuilder(
|
||||
txscript.WithScriptAllocSize(P2WSHSize),
|
||||
)
|
||||
|
||||
bldr.AddOp(txscript.OP_0)
|
||||
scriptHash := sha256.Sum256(witnessScript)
|
||||
bldr.AddData(scriptHash[:])
|
||||
return bldr.Script()
|
||||
return txscript.ScriptTemplate(
|
||||
`OP_0 {{ hex .ScriptHash }}`,
|
||||
txscript.WithScriptTemplateParams(TemplateParams{
|
||||
"ScriptHash": scriptHash[:],
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
// WitnessPubKeyHash generates a pay-to-witness-pubkey-hash public key script
|
||||
// paying to a version 0 witness program containing the passed serialized
|
||||
// public key.
|
||||
func WitnessPubKeyHash(pubkey []byte) ([]byte, error) {
|
||||
bldr := txscript.NewScriptBuilder(
|
||||
txscript.WithScriptAllocSize(P2WPKHSize),
|
||||
)
|
||||
|
||||
bldr.AddOp(txscript.OP_0)
|
||||
pkhash := btcutil.Hash160(pubkey)
|
||||
bldr.AddData(pkhash)
|
||||
return bldr.Script()
|
||||
return txscript.ScriptTemplate(
|
||||
`OP_0 {{ hex .PKHash }}`,
|
||||
txscript.WithScriptTemplateParams(TemplateParams{
|
||||
"PKHash": pkhash,
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
// GenerateP2SH generates a pay-to-script-hash public key script paying to the
|
||||
// passed redeem script.
|
||||
func GenerateP2SH(script []byte) ([]byte, error) {
|
||||
bldr := txscript.NewScriptBuilder(
|
||||
txscript.WithScriptAllocSize(NestedP2WPKHSize),
|
||||
scriptHash := btcutil.Hash160(script)
|
||||
return txscript.ScriptTemplate(
|
||||
`OP_HASH160 {{ hex .ScriptHash }} OP_EQUAL`,
|
||||
txscript.WithScriptTemplateParams(TemplateParams{
|
||||
"ScriptHash": scriptHash,
|
||||
}),
|
||||
)
|
||||
|
||||
bldr.AddOp(txscript.OP_HASH160)
|
||||
scripthash := btcutil.Hash160(script)
|
||||
bldr.AddData(scripthash)
|
||||
bldr.AddOp(txscript.OP_EQUAL)
|
||||
return bldr.Script()
|
||||
}
|
||||
|
||||
// GenerateP2PKH generates a pay-to-public-key-hash public key script paying to
|
||||
// the passed serialized public key.
|
||||
func GenerateP2PKH(pubkey []byte) ([]byte, error) {
|
||||
bldr := txscript.NewScriptBuilder(
|
||||
txscript.WithScriptAllocSize(P2PKHSize),
|
||||
pkHash := btcutil.Hash160(pubkey)
|
||||
return txscript.ScriptTemplate(
|
||||
`OP_DUP OP_HASH160 {{ hex .pkh }} OP_EQUALVERIFY OP_CHECKSIG`,
|
||||
txscript.WithScriptTemplateParams(TemplateParams{
|
||||
"pkh": pkHash,
|
||||
}),
|
||||
)
|
||||
|
||||
bldr.AddOp(txscript.OP_DUP)
|
||||
bldr.AddOp(txscript.OP_HASH160)
|
||||
pkhash := btcutil.Hash160(pubkey)
|
||||
bldr.AddData(pkhash)
|
||||
bldr.AddOp(txscript.OP_EQUALVERIFY)
|
||||
bldr.AddOp(txscript.OP_CHECKSIG)
|
||||
return bldr.Script()
|
||||
}
|
||||
|
||||
// GenerateUnknownWitness generates the maximum-sized witness public key script
|
||||
// consisting of a version push and a 40-byte data push.
|
||||
func GenerateUnknownWitness() ([]byte, error) {
|
||||
bldr := txscript.NewScriptBuilder()
|
||||
|
||||
bldr.AddOp(txscript.OP_0)
|
||||
witnessScript := make([]byte, 40)
|
||||
bldr.AddData(witnessScript)
|
||||
return bldr.Script()
|
||||
return txscript.ScriptTemplate(
|
||||
`OP_0 {{ hex .WitnessScript }}`,
|
||||
txscript.WithScriptTemplateParams(TemplateParams{
|
||||
"WitnessScript": witnessScript,
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
// GenMultiSigScript generates the non-p2sh'd multisig script for 2 of 2
|
||||
@@ -164,15 +161,13 @@ func GenMultiSigScript(aPub, bPub []byte) ([]byte, error) {
|
||||
aPub, bPub = bPub, aPub
|
||||
}
|
||||
|
||||
bldr := txscript.NewScriptBuilder(txscript.WithScriptAllocSize(
|
||||
MultiSigSize,
|
||||
))
|
||||
bldr.AddOp(txscript.OP_2)
|
||||
bldr.AddData(aPub) // Add both pubkeys (sorted).
|
||||
bldr.AddData(bPub)
|
||||
bldr.AddOp(txscript.OP_2)
|
||||
bldr.AddOp(txscript.OP_CHECKMULTISIG)
|
||||
return bldr.Script()
|
||||
return txscript.ScriptTemplate(
|
||||
`OP_2 {{ hex .pubA }} {{ hex .pubB }} OP_2 OP_CHECKMULTISIG`,
|
||||
txscript.WithScriptTemplateParams(TemplateParams{
|
||||
"pubA": aPub,
|
||||
"pubB": bPub,
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
// GenFundingPkScript creates a redeem script, and its matching p2wsh
|
||||
@@ -338,92 +333,40 @@ func SenderHTLCScript(senderHtlcKey, receiverHtlcKey,
|
||||
revocationKey *btcec.PublicKey, paymentHash []byte,
|
||||
confirmedSpend bool) ([]byte, error) {
|
||||
|
||||
builder := txscript.NewScriptBuilder(txscript.WithScriptAllocSize(
|
||||
OfferedHtlcScriptSizeConfirmed,
|
||||
))
|
||||
// Build the base script template
|
||||
scriptTemplate := `
|
||||
OP_DUP OP_HASH160 {{ hex .RevKeyHash }} OP_EQUAL
|
||||
OP_IF
|
||||
OP_CHECKSIG
|
||||
OP_ELSE
|
||||
{{ hex .ReceiverKey }}
|
||||
OP_SWAP OP_SIZE 32 OP_EQUAL
|
||||
OP_NOTIF
|
||||
OP_DROP 2 OP_SWAP {{ hex .SenderKey }} 2 OP_CHECKMULTISIG
|
||||
OP_ELSE
|
||||
OP_HASH160 {{ hex .PaymentHashRipemd }} OP_EQUALVERIFY
|
||||
OP_CHECKSIG
|
||||
OP_ENDIF
|
||||
`
|
||||
|
||||
// The opening operations are used to determine if this is the receiver
|
||||
// of the HTLC attempting to sweep all the funds due to a contract
|
||||
// breach. In this case, they'll place the revocation key at the top of
|
||||
// the stack.
|
||||
builder.AddOp(txscript.OP_DUP)
|
||||
builder.AddOp(txscript.OP_HASH160)
|
||||
builder.AddData(btcutil.Hash160(revocationKey.SerializeCompressed()))
|
||||
builder.AddOp(txscript.OP_EQUAL)
|
||||
|
||||
// If the hash matches, then this is the revocation clause. The output
|
||||
// can be spent if the check sig operation passes.
|
||||
builder.AddOp(txscript.OP_IF)
|
||||
builder.AddOp(txscript.OP_CHECKSIG)
|
||||
|
||||
// Otherwise, this may either be the receiver of the HTLC claiming with
|
||||
// the pre-image, or the sender of the HTLC sweeping the output after
|
||||
// it has timed out.
|
||||
builder.AddOp(txscript.OP_ELSE)
|
||||
|
||||
// We'll do a bit of set up by pushing the receiver's key on the top of
|
||||
// the stack. This will be needed later if we decide that this is the
|
||||
// sender activating the time out clause with the HTLC timeout
|
||||
// transaction.
|
||||
builder.AddData(receiverHtlcKey.SerializeCompressed())
|
||||
|
||||
// Atm, the top item of the stack is the receiverKey's so we use a swap
|
||||
// to expose what is either the payment pre-image or a signature.
|
||||
builder.AddOp(txscript.OP_SWAP)
|
||||
|
||||
// With the top item swapped, check if it's 32 bytes. If so, then this
|
||||
// *may* be the payment pre-image.
|
||||
builder.AddOp(txscript.OP_SIZE)
|
||||
builder.AddInt64(32)
|
||||
builder.AddOp(txscript.OP_EQUAL)
|
||||
|
||||
// If it isn't then this might be the sender of the HTLC activating the
|
||||
// time out clause.
|
||||
builder.AddOp(txscript.OP_NOTIF)
|
||||
|
||||
// We'll drop the OP_IF return value off the top of the stack so we can
|
||||
// reconstruct the multi-sig script used as an off-chain covenant. If
|
||||
// two valid signatures are provided, then the output will be deemed as
|
||||
// spendable.
|
||||
builder.AddOp(txscript.OP_DROP)
|
||||
builder.AddOp(txscript.OP_2)
|
||||
builder.AddOp(txscript.OP_SWAP)
|
||||
builder.AddData(senderHtlcKey.SerializeCompressed())
|
||||
builder.AddOp(txscript.OP_2)
|
||||
builder.AddOp(txscript.OP_CHECKMULTISIG)
|
||||
|
||||
// Otherwise, then the only other case is that this is the receiver of
|
||||
// the HTLC sweeping it on-chain with the payment pre-image.
|
||||
builder.AddOp(txscript.OP_ELSE)
|
||||
|
||||
// Hash the top item of the stack and compare it with the hash160 of
|
||||
// the payment hash, which is already the sha256 of the payment
|
||||
// pre-image. By using this little trick we're able to save space
|
||||
// on-chain as the witness includes a 20-byte hash rather than a
|
||||
// 32-byte hash.
|
||||
builder.AddOp(txscript.OP_HASH160)
|
||||
builder.AddData(Ripemd160H(paymentHash))
|
||||
builder.AddOp(txscript.OP_EQUALVERIFY)
|
||||
|
||||
// This checks the receiver's signature so that a third party with
|
||||
// knowledge of the payment preimage still cannot steal the output.
|
||||
builder.AddOp(txscript.OP_CHECKSIG)
|
||||
|
||||
// Close out the OP_IF statement above.
|
||||
builder.AddOp(txscript.OP_ENDIF)
|
||||
|
||||
// Add 1 block CSV delay if a confirmation is required for the
|
||||
// non-revocation clauses.
|
||||
// Add 1 block CSV delay if a confirmation is required.
|
||||
if confirmedSpend {
|
||||
builder.AddOp(txscript.OP_1)
|
||||
builder.AddOp(txscript.OP_CHECKSEQUENCEVERIFY)
|
||||
builder.AddOp(txscript.OP_DROP)
|
||||
scriptTemplate += ` OP_1 OP_CHECKSEQUENCEVERIFY OP_DROP`
|
||||
}
|
||||
|
||||
// Close out the OP_IF statement at the top of the script.
|
||||
builder.AddOp(txscript.OP_ENDIF)
|
||||
// Close out the top level if statement.
|
||||
scriptTemplate += ` OP_ENDIF`
|
||||
|
||||
return builder.Script()
|
||||
// Use the ScriptTemplate function with the properly formatted template
|
||||
return txscript.ScriptTemplate(
|
||||
scriptTemplate,
|
||||
txscript.WithScriptTemplateParams(TemplateParams{
|
||||
"RevKeyHash": btcutil.Hash160(revocationKey.SerializeCompressed()), //nolint:ll
|
||||
"ReceiverKey": receiverHtlcKey.SerializeCompressed(), //nolint:ll
|
||||
"SenderKey": senderHtlcKey.SerializeCompressed(), //nolint:ll
|
||||
"PaymentHashRipemd": Ripemd160H(paymentHash),
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
// SenderHtlcSpendRevokeWithKey constructs a valid witness allowing the receiver of an
|
||||
@@ -559,14 +502,15 @@ func SenderHtlcSpendTimeout(receiverSig Signature,
|
||||
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()
|
||||
timeoutLeafScript, err := txscript.ScriptTemplate(
|
||||
`
|
||||
{{ hex .SenderKey }} OP_CHECKSIGVERIFY
|
||||
{{ hex .ReceiverKey }} OP_CHECKSIG`,
|
||||
txscript.WithScriptTemplateParams(TemplateParams{
|
||||
"SenderKey": schnorr.SerializePubKey(senderHtlcKey),
|
||||
"ReceiverKey": schnorr.SerializePubKey(receiverHtlcKey),
|
||||
}),
|
||||
)
|
||||
if err != nil {
|
||||
return txscript.TapLeaf{}, err
|
||||
}
|
||||
@@ -585,28 +529,19 @@ func SenderHTLCTapLeafTimeout(senderHtlcKey,
|
||||
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-image 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_1)
|
||||
builder.AddOp(txscript.OP_CHECKSEQUENCEVERIFY)
|
||||
builder.AddOp(txscript.OP_DROP)
|
||||
|
||||
successLeafScript, err := builder.Script()
|
||||
successLeafScript, err := txscript.ScriptTemplate(
|
||||
`
|
||||
OP_SIZE 32 OP_EQUALVERIFY OP_HASH160
|
||||
{{ hex .PaymentHashRipemd }} OP_EQUALVERIFY
|
||||
{{ hex .ReceiverKey }} OP_CHECKSIG
|
||||
OP_1 OP_CHECKSEQUENCEVERIFY OP_DROP`,
|
||||
txscript.WithScriptTemplateParams(TemplateParams{
|
||||
"PaymentHashRipemd": Ripemd160H(paymentHash),
|
||||
"ReceiverKey": schnorr.SerializePubKey(
|
||||
receiverHtlcKey,
|
||||
),
|
||||
}),
|
||||
)
|
||||
if err != nil {
|
||||
return txscript.TapLeaf{}, err
|
||||
}
|
||||
@@ -987,101 +922,44 @@ func ReceiverHTLCScript(cltvExpiry uint32, senderHtlcKey,
|
||||
receiverHtlcKey, revocationKey *btcec.PublicKey,
|
||||
paymentHash []byte, confirmedSpend bool) ([]byte, error) {
|
||||
|
||||
builder := txscript.NewScriptBuilder(txscript.WithScriptAllocSize(
|
||||
AcceptedHtlcScriptSizeConfirmed,
|
||||
))
|
||||
|
||||
// The opening operations are used to determine if this is the sender
|
||||
// of the HTLC attempting to sweep all the funds due to a contract
|
||||
// breach. In this case, they'll place the revocation key at the top of
|
||||
// the stack.
|
||||
builder.AddOp(txscript.OP_DUP)
|
||||
builder.AddOp(txscript.OP_HASH160)
|
||||
builder.AddData(btcutil.Hash160(revocationKey.SerializeCompressed()))
|
||||
builder.AddOp(txscript.OP_EQUAL)
|
||||
|
||||
// If the hash matches, then this is the revocation clause. The output
|
||||
// can be spent if the check sig operation passes.
|
||||
builder.AddOp(txscript.OP_IF)
|
||||
builder.AddOp(txscript.OP_CHECKSIG)
|
||||
|
||||
// Otherwise, this may either be the receiver of the HTLC starting the
|
||||
// claiming process via the second level HTLC success transaction and
|
||||
// the pre-image, or the sender of the HTLC sweeping the output after
|
||||
// it has timed out.
|
||||
builder.AddOp(txscript.OP_ELSE)
|
||||
|
||||
// We'll do a bit of set up by pushing the sender's key on the top of
|
||||
// the stack. This will be needed later if we decide that this is the
|
||||
// receiver transitioning the output to the claim state using their
|
||||
// second-level HTLC success transaction.
|
||||
builder.AddData(senderHtlcKey.SerializeCompressed())
|
||||
|
||||
// Atm, the top item of the stack is the sender's key so we use a swap
|
||||
// to expose what is either the payment pre-image or something else.
|
||||
builder.AddOp(txscript.OP_SWAP)
|
||||
|
||||
// With the top item swapped, check if it's 32 bytes. If so, then this
|
||||
// *may* be the payment pre-image.
|
||||
builder.AddOp(txscript.OP_SIZE)
|
||||
builder.AddInt64(32)
|
||||
builder.AddOp(txscript.OP_EQUAL)
|
||||
|
||||
// If the item on the top of the stack is 32-bytes, then it is the
|
||||
// proper size, so this indicates that the receiver of the HTLC is
|
||||
// attempting to claim the output on-chain by transitioning the state
|
||||
// of the HTLC to delay+claim.
|
||||
builder.AddOp(txscript.OP_IF)
|
||||
|
||||
// Next we'll hash the item on the top of the stack, if it matches the
|
||||
// payment pre-image, then we'll continue. Otherwise, we'll end the
|
||||
// script here as this is the invalid payment pre-image.
|
||||
builder.AddOp(txscript.OP_HASH160)
|
||||
builder.AddData(Ripemd160H(paymentHash))
|
||||
builder.AddOp(txscript.OP_EQUALVERIFY)
|
||||
|
||||
// If the payment hash matches, then we'll also need to satisfy the
|
||||
// multi-sig covenant by providing both signatures of the sender and
|
||||
// receiver. If the convenient is met, then we'll allow the spending of
|
||||
// this output, but only by the HTLC success transaction.
|
||||
builder.AddOp(txscript.OP_2)
|
||||
builder.AddOp(txscript.OP_SWAP)
|
||||
builder.AddData(receiverHtlcKey.SerializeCompressed())
|
||||
builder.AddOp(txscript.OP_2)
|
||||
builder.AddOp(txscript.OP_CHECKMULTISIG)
|
||||
|
||||
// Otherwise, this might be the sender of the HTLC attempting to sweep
|
||||
// it on-chain after the timeout.
|
||||
builder.AddOp(txscript.OP_ELSE)
|
||||
|
||||
// We'll drop the extra item (which is the output from evaluating the
|
||||
// OP_EQUAL) above from the stack.
|
||||
builder.AddOp(txscript.OP_DROP)
|
||||
|
||||
// With that item dropped off, we can now enforce the absolute
|
||||
// lock-time required to timeout the HTLC. If the time has passed, then
|
||||
// we'll proceed with a checksig to ensure that this is actually the
|
||||
// sender of he original HTLC.
|
||||
builder.AddInt64(int64(cltvExpiry))
|
||||
builder.AddOp(txscript.OP_CHECKLOCKTIMEVERIFY)
|
||||
builder.AddOp(txscript.OP_DROP)
|
||||
builder.AddOp(txscript.OP_CHECKSIG)
|
||||
|
||||
// Close out the inner if statement.
|
||||
builder.AddOp(txscript.OP_ENDIF)
|
||||
scriptTemplate := `
|
||||
OP_DUP OP_HASH160 {{ hex .RevKeyHash }} OP_EQUAL
|
||||
OP_IF
|
||||
OP_CHECKSIG
|
||||
OP_ELSE
|
||||
{{ hex .SenderKey }}
|
||||
OP_SWAP OP_SIZE 32 OP_EQUAL
|
||||
OP_IF
|
||||
OP_HASH160 {{ hex .PaymentHashRipemd }} OP_EQUALVERIFY
|
||||
OP_2 OP_SWAP {{ hex .ReceiverKey }} OP_2 OP_CHECKMULTISIG
|
||||
OP_ELSE
|
||||
OP_DROP {{ .CltvExpiry }} OP_CHECKLOCKTIMEVERIFY OP_DROP
|
||||
OP_CHECKSIG
|
||||
OP_ENDIF
|
||||
`
|
||||
|
||||
// Add 1 block CSV delay for non-revocation clauses if confirmation is
|
||||
// required.
|
||||
if confirmedSpend {
|
||||
builder.AddOp(txscript.OP_1)
|
||||
builder.AddOp(txscript.OP_CHECKSEQUENCEVERIFY)
|
||||
builder.AddOp(txscript.OP_DROP)
|
||||
scriptTemplate += ` OP_1 OP_CHECKSEQUENCEVERIFY OP_DROP`
|
||||
}
|
||||
|
||||
// Close out the outer if statement.
|
||||
builder.AddOp(txscript.OP_ENDIF)
|
||||
scriptTemplate += ` OP_ENDIF`
|
||||
|
||||
return builder.Script()
|
||||
// Use the ScriptTemplate function with the properly formatted template
|
||||
return txscript.ScriptTemplate(
|
||||
scriptTemplate,
|
||||
txscript.WithScriptTemplateParams(TemplateParams{
|
||||
"RevKeyHash": btcutil.Hash160(
|
||||
revocationKey.SerializeCompressed(),
|
||||
),
|
||||
"SenderKey": senderHtlcKey.SerializeCompressed(), //nolint:ll
|
||||
"ReceiverKey": receiverHtlcKey.SerializeCompressed(), //nolint:ll
|
||||
"PaymentHashRipemd": Ripemd160H(paymentHash),
|
||||
"CltvExpiry": int64(cltvExpiry),
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
// ReceiverHtlcSpendRedeem constructs a valid witness allowing the receiver of
|
||||
@@ -1230,23 +1108,19 @@ func ReceiverHtlcSpendTimeout(signer Signer, signDesc *SignDescriptor,
|
||||
func ReceiverHtlcTapLeafTimeout(senderHtlcKey *btcec.PublicKey,
|
||||
cltvExpiry uint32) (txscript.TapLeaf, error) {
|
||||
|
||||
builder := txscript.NewScriptBuilder()
|
||||
|
||||
// The first part of the script will verify a signature from the
|
||||
// sender authorizing the spend (the timeout).
|
||||
builder.AddData(schnorr.SerializePubKey(senderHtlcKey))
|
||||
builder.AddOp(txscript.OP_CHECKSIG)
|
||||
builder.AddOp(txscript.OP_1)
|
||||
builder.AddOp(txscript.OP_CHECKSEQUENCEVERIFY)
|
||||
builder.AddOp(txscript.OP_DROP)
|
||||
|
||||
// The second portion will ensure that the CLTV expiry on the spending
|
||||
// transaction is correct.
|
||||
builder.AddInt64(int64(cltvExpiry))
|
||||
builder.AddOp(txscript.OP_CHECKLOCKTIMEVERIFY)
|
||||
builder.AddOp(txscript.OP_DROP)
|
||||
|
||||
timeoutLeafScript, err := builder.Script()
|
||||
// The first part of the script will verify a signature from the sender
|
||||
// authorizing the spend (the timeout). The second portion will ensure
|
||||
// that the CLTV expiry on the spending transaction is correct.
|
||||
timeoutLeafScript, err := txscript.ScriptTemplate(
|
||||
`
|
||||
{{ hex .SenderKey }} OP_CHECKSIG
|
||||
OP_1 OP_CHECKSEQUENCEVERIFY OP_DROP
|
||||
{{ .CltvExpiry }} OP_CHECKLOCKTIMEVERIFY OP_DROP`,
|
||||
txscript.WithScriptTemplateParams(TemplateParams{
|
||||
"SenderKey": schnorr.SerializePubKey(senderHtlcKey),
|
||||
"CltvExpiry": int64(cltvExpiry),
|
||||
}),
|
||||
)
|
||||
if err != nil {
|
||||
return txscript.TapLeaf{}, err
|
||||
}
|
||||
@@ -1266,27 +1140,24 @@ func ReceiverHtlcTapLeafSuccess(receiverHtlcKey *btcec.PublicKey,
|
||||
senderHtlcKey *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-image matches what we hard code into
|
||||
// the script.
|
||||
builder.AddOp(txscript.OP_HASH160)
|
||||
builder.AddData(Ripemd160H(paymentHash))
|
||||
builder.AddOp(txscript.OP_EQUALVERIFY)
|
||||
|
||||
// Verify the "2-of-2" multi-sig that requires both parties to sign
|
||||
// off.
|
||||
builder.AddData(schnorr.SerializePubKey(receiverHtlcKey))
|
||||
builder.AddOp(txscript.OP_CHECKSIGVERIFY)
|
||||
builder.AddData(schnorr.SerializePubKey(senderHtlcKey))
|
||||
builder.AddOp(txscript.OP_CHECKSIG)
|
||||
|
||||
successLeafScript, err := builder.Script()
|
||||
// Check that the pre-image is 32 bytes as required. We also check that
|
||||
// the specified pre-image matches what we hard code into the script.
|
||||
// Finally, verify the "2-of-2" multi-sig that requires both parties to
|
||||
// sign off.
|
||||
successLeafScript, err := txscript.ScriptTemplate(
|
||||
`
|
||||
OP_SIZE 32 OP_EQUALVERIFY OP_HASH160
|
||||
{{ hex .PaymentHashRipemd }} OP_EQUALVERIFY
|
||||
{{ hex .ReceiverKey }} OP_CHECKSIGVERIFY
|
||||
{{ hex .SenderKey }} OP_CHECKSIG`,
|
||||
txscript.WithScriptTemplateParams(TemplateParams{
|
||||
"PaymentHashRipemd": Ripemd160H(paymentHash),
|
||||
"ReceiverKey": schnorr.SerializePubKey(
|
||||
receiverHtlcKey,
|
||||
),
|
||||
"SenderKey": schnorr.SerializePubKey(senderHtlcKey),
|
||||
}),
|
||||
)
|
||||
if err != nil {
|
||||
return txscript.TapLeaf{}, err
|
||||
}
|
||||
@@ -1547,43 +1418,34 @@ func ReceiverHTLCScriptTaprootRevoke(signer Signer, signDesc *SignDescriptor,
|
||||
func SecondLevelHtlcScript(revocationKey, delayKey *btcec.PublicKey,
|
||||
csvDelay uint32) ([]byte, error) {
|
||||
|
||||
builder := txscript.NewScriptBuilder(txscript.WithScriptAllocSize(
|
||||
ToLocalScriptSize,
|
||||
))
|
||||
|
||||
// If this is the revocation clause for this script is to be executed,
|
||||
// the spender will push a 1, forcing us to hit the true clause of this
|
||||
// if statement.
|
||||
builder.AddOp(txscript.OP_IF)
|
||||
|
||||
// If this is the revocation case, then we'll push the revocation
|
||||
// public key on the stack.
|
||||
builder.AddData(revocationKey.SerializeCompressed())
|
||||
|
||||
// Otherwise, this is either the sender or receiver of the HTLC
|
||||
// attempting to claim the HTLC output.
|
||||
builder.AddOp(txscript.OP_ELSE)
|
||||
|
||||
// In order to give the other party time to execute the revocation
|
||||
// clause above, we require a relative timeout to pass before the
|
||||
// output can be spent.
|
||||
builder.AddInt64(int64(csvDelay))
|
||||
builder.AddOp(txscript.OP_CHECKSEQUENCEVERIFY)
|
||||
builder.AddOp(txscript.OP_DROP)
|
||||
|
||||
// If the relative timelock passes, then we'll add the delay key to the
|
||||
// stack to ensure that we properly authenticate the spending party.
|
||||
builder.AddData(delayKey.SerializeCompressed())
|
||||
|
||||
// Close out the if statement.
|
||||
builder.AddOp(txscript.OP_ENDIF)
|
||||
|
||||
// In either case, we'll ensure that only either the party possessing
|
||||
// the revocation private key, or the delay private key is able to
|
||||
// spend this output.
|
||||
builder.AddOp(txscript.OP_CHECKSIG)
|
||||
|
||||
return builder.Script()
|
||||
return txscript.ScriptTemplate(
|
||||
`OP_IF
|
||||
{{ hex .RevokeKey }}
|
||||
OP_ELSE
|
||||
{{ .CsvDelay }} OP_CHECKSEQUENCEVERIFY OP_DROP
|
||||
{{ hex .DelayKey }}
|
||||
OP_ENDIF OP_CHECKSIG`,
|
||||
txscript.WithScriptTemplateParams(TemplateParams{
|
||||
"RevokeKey": revocationKey.SerializeCompressed(),
|
||||
"CsvDelay": int64(csvDelay),
|
||||
"DelayKey": delayKey.SerializeCompressed(),
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
// TODO(roasbeef): move all taproot stuff to new file?
|
||||
@@ -1598,20 +1460,19 @@ func SecondLevelHtlcScript(revocationKey, delayKey *btcec.PublicKey,
|
||||
func TaprootSecondLevelTapLeaf(delayKey *btcec.PublicKey,
|
||||
csvDelay uint32) (txscript.TapLeaf, error) {
|
||||
|
||||
builder := txscript.NewScriptBuilder()
|
||||
|
||||
// Ensure the proper party can sign for this output.
|
||||
builder.AddData(schnorr.SerializePubKey(delayKey))
|
||||
builder.AddOp(txscript.OP_CHECKSIG)
|
||||
|
||||
// Assuming the above passes, then we'll now ensure that the CSV delay
|
||||
// has been upheld, dropping the int we pushed on. If the sig above is
|
||||
// valid, then a 1 will be left on the stack.
|
||||
builder.AddInt64(int64(csvDelay))
|
||||
builder.AddOp(txscript.OP_CHECKSEQUENCEVERIFY)
|
||||
builder.AddOp(txscript.OP_DROP)
|
||||
|
||||
secondLevelLeafScript, err := builder.Script()
|
||||
secondLevelLeafScript, err := txscript.ScriptTemplate(
|
||||
`
|
||||
{{ hex .DelayKey }} OP_CHECKSIG
|
||||
{{ .CsvDelay }} OP_CHECKSEQUENCEVERIFY OP_DROP`,
|
||||
txscript.WithScriptTemplateParams(TemplateParams{
|
||||
"DelayKey": schnorr.SerializePubKey(delayKey),
|
||||
"CsvDelay": int64(csvDelay),
|
||||
}),
|
||||
)
|
||||
if err != nil {
|
||||
return txscript.TapLeaf{}, err
|
||||
}
|
||||
@@ -1880,50 +1741,25 @@ func TaprootHtlcSpendSuccess(signer Signer, signDesc *SignDescriptor,
|
||||
func LeaseSecondLevelHtlcScript(revocationKey, delayKey *btcec.PublicKey,
|
||||
csvDelay, cltvExpiry uint32) ([]byte, error) {
|
||||
|
||||
builder := txscript.NewScriptBuilder(txscript.WithScriptAllocSize(
|
||||
ToLocalScriptSize + LeaseWitnessScriptSizeOverhead,
|
||||
))
|
||||
|
||||
// If this is the revocation clause for this script is to be executed,
|
||||
// the spender will push a 1, forcing us to hit the true clause of this
|
||||
// if statement.
|
||||
builder.AddOp(txscript.OP_IF)
|
||||
|
||||
// If this this is the revocation case, then we'll push the revocation
|
||||
// public key on the stack.
|
||||
builder.AddData(revocationKey.SerializeCompressed())
|
||||
|
||||
// Otherwise, this is either the sender or receiver of the HTLC
|
||||
// attempting to claim the HTLC output.
|
||||
builder.AddOp(txscript.OP_ELSE)
|
||||
|
||||
// The channel initiator always has the additional channel lease
|
||||
// expiration constraint for outputs that pay to them which must be
|
||||
// satisfied.
|
||||
builder.AddInt64(int64(cltvExpiry))
|
||||
builder.AddOp(txscript.OP_CHECKLOCKTIMEVERIFY)
|
||||
builder.AddOp(txscript.OP_DROP)
|
||||
|
||||
// In order to give the other party time to execute the revocation
|
||||
// clause above, we require a relative timeout to pass before the
|
||||
// output can be spent.
|
||||
builder.AddInt64(int64(csvDelay))
|
||||
builder.AddOp(txscript.OP_CHECKSEQUENCEVERIFY)
|
||||
builder.AddOp(txscript.OP_DROP)
|
||||
|
||||
// If the relative timelock passes, then we'll add the delay key to the
|
||||
// stack to ensure that we properly authenticate the spending party.
|
||||
builder.AddData(delayKey.SerializeCompressed())
|
||||
|
||||
// Close out the if statement.
|
||||
builder.AddOp(txscript.OP_ENDIF)
|
||||
|
||||
// In either case, we'll ensure that only either the party possessing
|
||||
// the revocation private key, or the delay private key is able to
|
||||
// spend this output.
|
||||
builder.AddOp(txscript.OP_CHECKSIG)
|
||||
|
||||
return builder.Script()
|
||||
// Build a script template with conditional paths for revocation and normal spending
|
||||
// If this is the revocation clause, the spender will push a 1, forcing the first path
|
||||
// Otherwise, this is either the sender or receiver of the HTLC attempting to claim
|
||||
return txscript.ScriptTemplate(
|
||||
`
|
||||
OP_IF
|
||||
{{ hex .RevokeKey }}
|
||||
OP_ELSE
|
||||
{{ .CltvExpiry }} OP_CHECKLOCKTIMEVERIFY OP_DROP
|
||||
{{ .CsvDelay }} OP_CHECKSEQUENCEVERIFY OP_DROP
|
||||
{{ hex .DelayKey }}
|
||||
OP_ENDIF OP_CHECKSIG`,
|
||||
txscript.WithScriptTemplateParams(TemplateParams{
|
||||
"RevokeKey": revocationKey.SerializeCompressed(),
|
||||
"CltvExpiry": int64(cltvExpiry),
|
||||
"CsvDelay": int64(csvDelay),
|
||||
"DelayKey": delayKey.SerializeCompressed(),
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
// HtlcSpendSuccess spends a second-level HTLC output. This function is to be
|
||||
@@ -2065,32 +1901,21 @@ func CommitScriptToSelf(csvTimeout uint32, selfKey, revokeKey *btcec.PublicKey)
|
||||
// have divulged the revocation hash, allowing them to homomorphically
|
||||
// derive the proper private key which corresponds to the revoke public
|
||||
// key.
|
||||
builder := txscript.NewScriptBuilder(txscript.WithScriptAllocSize(
|
||||
ToLocalScriptSize,
|
||||
))
|
||||
|
||||
builder.AddOp(txscript.OP_IF)
|
||||
|
||||
// If a valid signature using the revocation key is presented, then
|
||||
// allow an immediate spend provided the proper signature.
|
||||
builder.AddData(revokeKey.SerializeCompressed())
|
||||
|
||||
builder.AddOp(txscript.OP_ELSE)
|
||||
|
||||
// Otherwise, we can re-claim our funds after a CSV delay of
|
||||
// 'csvTimeout' timeout blocks, and a valid signature.
|
||||
builder.AddInt64(int64(csvTimeout))
|
||||
builder.AddOp(txscript.OP_CHECKSEQUENCEVERIFY)
|
||||
builder.AddOp(txscript.OP_DROP)
|
||||
builder.AddData(selfKey.SerializeCompressed())
|
||||
|
||||
builder.AddOp(txscript.OP_ENDIF)
|
||||
|
||||
// Finally, we'll validate the signature against the public key that's
|
||||
// left on the top of the stack.
|
||||
builder.AddOp(txscript.OP_CHECKSIG)
|
||||
|
||||
return builder.Script()
|
||||
return txscript.ScriptTemplate(
|
||||
`
|
||||
OP_IF
|
||||
{{ hex .RevokeKey }}
|
||||
OP_ELSE
|
||||
{{ .CsvTimeout }} OP_CHECKSEQUENCEVERIFY OP_DROP
|
||||
{{ hex .SelfKey }}
|
||||
OP_ENDIF
|
||||
OP_CHECKSIG`,
|
||||
txscript.WithScriptTemplateParams(TemplateParams{
|
||||
"RevokeKey": revokeKey.SerializeCompressed(),
|
||||
"CsvTimeout": int64(csvTimeout),
|
||||
"SelfKey": selfKey.SerializeCompressed(),
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
// CommitScriptTree holds the taproot output key (in this case the revocation
|
||||
@@ -2230,14 +2055,15 @@ func NewLocalCommitScriptTree(csvTimeout uint32, selfKey,
|
||||
func TaprootLocalCommitDelayScript(csvTimeout uint32,
|
||||
selfKey *btcec.PublicKey) ([]byte, error) {
|
||||
|
||||
builder := txscript.NewScriptBuilder()
|
||||
builder.AddData(schnorr.SerializePubKey(selfKey))
|
||||
builder.AddOp(txscript.OP_CHECKSIG)
|
||||
builder.AddInt64(int64(csvTimeout))
|
||||
builder.AddOp(txscript.OP_CHECKSEQUENCEVERIFY)
|
||||
builder.AddOp(txscript.OP_DROP)
|
||||
|
||||
return builder.Script()
|
||||
return txscript.ScriptTemplate(
|
||||
`
|
||||
{{ hex .SelfKey }} OP_CHECKSIG
|
||||
{{ .CsvTimeout }} OP_CHECKSEQUENCEVERIFY OP_DROP`,
|
||||
txscript.WithScriptTemplateParams(TemplateParams{
|
||||
"SelfKey": schnorr.SerializePubKey(selfKey),
|
||||
"CsvTimeout": int64(csvTimeout),
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
// TaprootLocalCommitRevokeScript builds the tap leaf with the revocation path
|
||||
@@ -2245,13 +2071,13 @@ func TaprootLocalCommitDelayScript(csvTimeout uint32,
|
||||
func TaprootLocalCommitRevokeScript(selfKey, revokeKey *btcec.PublicKey) (
|
||||
[]byte, error) {
|
||||
|
||||
builder := txscript.NewScriptBuilder()
|
||||
builder.AddData(schnorr.SerializePubKey(selfKey))
|
||||
builder.AddOp(txscript.OP_DROP)
|
||||
builder.AddData(schnorr.SerializePubKey(revokeKey))
|
||||
builder.AddOp(txscript.OP_CHECKSIG)
|
||||
|
||||
return builder.Script()
|
||||
return txscript.ScriptTemplate(
|
||||
`{{ hex .SelfKey }} OP_DROP {{ hex .RevokeKey }} OP_CHECKSIG`,
|
||||
txscript.WithScriptTemplateParams(TemplateParams{
|
||||
"SelfKey": schnorr.SerializePubKey(selfKey),
|
||||
"RevokeKey": schnorr.SerializePubKey(revokeKey),
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
// TaprootCommitScriptToSelf creates the taproot witness program that commits
|
||||
@@ -2430,38 +2256,23 @@ func LeaseCommitScriptToSelf(selfKey, revokeKey *btcec.PublicKey,
|
||||
// have divulged the revocation hash, allowing them to homomorphically
|
||||
// derive the proper private key which corresponds to the revoke public
|
||||
// key.
|
||||
builder := txscript.NewScriptBuilder(txscript.WithScriptAllocSize(
|
||||
ToLocalScriptSize + LeaseWitnessScriptSizeOverhead,
|
||||
))
|
||||
|
||||
builder.AddOp(txscript.OP_IF)
|
||||
|
||||
// If a valid signature using the revocation key is presented, then
|
||||
// allow an immediate spend provided the proper signature.
|
||||
builder.AddData(revokeKey.SerializeCompressed())
|
||||
|
||||
builder.AddOp(txscript.OP_ELSE)
|
||||
|
||||
// Otherwise, we can re-claim our funds after once the CLTV lease
|
||||
// maturity has been met, along with the CSV delay of 'csvTimeout'
|
||||
// timeout blocks, and a valid signature.
|
||||
builder.AddInt64(int64(leaseExpiry))
|
||||
builder.AddOp(txscript.OP_CHECKLOCKTIMEVERIFY)
|
||||
builder.AddOp(txscript.OP_DROP)
|
||||
|
||||
builder.AddInt64(int64(csvTimeout))
|
||||
builder.AddOp(txscript.OP_CHECKSEQUENCEVERIFY)
|
||||
builder.AddOp(txscript.OP_DROP)
|
||||
|
||||
builder.AddData(selfKey.SerializeCompressed())
|
||||
|
||||
builder.AddOp(txscript.OP_ENDIF)
|
||||
|
||||
// Finally, we'll validate the signature against the public key that's
|
||||
// left on the top of the stack.
|
||||
builder.AddOp(txscript.OP_CHECKSIG)
|
||||
|
||||
return builder.Script()
|
||||
return txscript.ScriptTemplate(
|
||||
`
|
||||
OP_IF
|
||||
{{ hex .RevokeKey }}
|
||||
OP_ELSE
|
||||
{{ .LeaseExpiry }} OP_CHECKLOCKTIMEVERIFY OP_DROP
|
||||
{{ .CsvTimeout }} OP_CHECKSEQUENCEVERIFY OP_DROP
|
||||
{{ hex .SelfKey }}
|
||||
OP_ENDIF
|
||||
OP_CHECKSIG`,
|
||||
txscript.WithScriptTemplateParams(TemplateParams{
|
||||
"RevokeKey": revokeKey.SerializeCompressed(),
|
||||
"LeaseExpiry": int64(leaseExpiry),
|
||||
"CsvTimeout": int64(csvTimeout),
|
||||
"SelfKey": selfKey.SerializeCompressed(),
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
// CommitSpendTimeout constructs a valid witness allowing the owner of a
|
||||
@@ -2577,13 +2388,12 @@ func CommitSpendNoDelay(signer Signer, signDesc *SignDescriptor,
|
||||
// p2wkh output spendable immediately, requiring no contestation period.
|
||||
func CommitScriptUnencumbered(key *btcec.PublicKey) ([]byte, error) {
|
||||
// This script goes to the "other" party, and is spendable immediately.
|
||||
builder := txscript.NewScriptBuilder(txscript.WithScriptAllocSize(
|
||||
P2WPKHSize,
|
||||
))
|
||||
builder.AddOp(txscript.OP_0)
|
||||
builder.AddData(btcutil.Hash160(key.SerializeCompressed()))
|
||||
|
||||
return builder.Script()
|
||||
return txscript.ScriptTemplate(
|
||||
`OP_0 {{ hex .PKHash }}`,
|
||||
txscript.WithScriptTemplateParams(TemplateParams{
|
||||
"PKHash": btcutil.Hash160(key.SerializeCompressed()),
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
// CommitScriptToRemoteConfirmed constructs the script for the output on the
|
||||
@@ -2599,19 +2409,15 @@ func CommitScriptUnencumbered(key *btcec.PublicKey) ([]byte, error) {
|
||||
// <key> OP_CHECKSIGVERIFY
|
||||
// 1 OP_CHECKSEQUENCEVERIFY
|
||||
func CommitScriptToRemoteConfirmed(key *btcec.PublicKey) ([]byte, error) {
|
||||
builder := txscript.NewScriptBuilder(txscript.WithScriptAllocSize(
|
||||
ToRemoteConfirmedScriptSize,
|
||||
))
|
||||
|
||||
// Only the given key can spend the output.
|
||||
builder.AddData(key.SerializeCompressed())
|
||||
builder.AddOp(txscript.OP_CHECKSIGVERIFY)
|
||||
|
||||
// Check that the it has one confirmation.
|
||||
builder.AddOp(txscript.OP_1)
|
||||
builder.AddOp(txscript.OP_CHECKSEQUENCEVERIFY)
|
||||
|
||||
return builder.Script()
|
||||
// Only the given key can spend the output after one confirmation.
|
||||
return txscript.ScriptTemplate(
|
||||
`
|
||||
{{ hex .Key }} OP_CHECKSIGVERIFY
|
||||
OP_1 OP_CHECKSEQUENCEVERIFY`,
|
||||
txscript.WithScriptTemplateParams(TemplateParams{
|
||||
"Key": key.SerializeCompressed(),
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
// NewRemoteCommitScriptTree constructs a new script tree for the remote party
|
||||
@@ -2621,14 +2427,14 @@ func NewRemoteCommitScriptTree(remoteKey *btcec.PublicKey,
|
||||
|
||||
// First, construct the remote party's tapscript they'll use to sweep
|
||||
// their outputs.
|
||||
builder := txscript.NewScriptBuilder()
|
||||
builder.AddData(schnorr.SerializePubKey(remoteKey))
|
||||
builder.AddOp(txscript.OP_CHECKSIG)
|
||||
builder.AddOp(txscript.OP_1)
|
||||
builder.AddOp(txscript.OP_CHECKSEQUENCEVERIFY)
|
||||
builder.AddOp(txscript.OP_DROP)
|
||||
|
||||
remoteScript, err := builder.Script()
|
||||
remoteScript, err := txscript.ScriptTemplate(
|
||||
`
|
||||
{{ hex .RemoteKey }} OP_CHECKSIG
|
||||
OP_1 OP_CHECKSEQUENCEVERIFY OP_DROP`,
|
||||
txscript.WithScriptTemplateParams(TemplateParams{
|
||||
"RemoteKey": schnorr.SerializePubKey(remoteKey),
|
||||
}),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -2743,24 +2549,18 @@ func TaprootCommitRemoteSpend(signer Signer, signDesc *SignDescriptor,
|
||||
func LeaseCommitScriptToRemoteConfirmed(key *btcec.PublicKey,
|
||||
leaseExpiry uint32) ([]byte, error) {
|
||||
|
||||
builder := txscript.NewScriptBuilder(txscript.WithScriptAllocSize(45))
|
||||
|
||||
// Only the given key can spend the output.
|
||||
builder.AddData(key.SerializeCompressed())
|
||||
builder.AddOp(txscript.OP_CHECKSIGVERIFY)
|
||||
|
||||
// The channel initiator always has the additional channel lease
|
||||
// expiration constraint for outputs that pay to them which must be
|
||||
// satisfied.
|
||||
builder.AddInt64(int64(leaseExpiry))
|
||||
builder.AddOp(txscript.OP_CHECKLOCKTIMEVERIFY)
|
||||
builder.AddOp(txscript.OP_DROP)
|
||||
|
||||
// Check that it has one confirmation.
|
||||
builder.AddOp(txscript.OP_1)
|
||||
builder.AddOp(txscript.OP_CHECKSEQUENCEVERIFY)
|
||||
|
||||
return builder.Script()
|
||||
// This script adds lease expiration constraint in addition to the
|
||||
// standard remote confirmed script requirements.
|
||||
return txscript.ScriptTemplate(
|
||||
`
|
||||
{{ hex .Key }} OP_CHECKSIGVERIFY
|
||||
{{ .LeaseExpiry }} OP_CHECKLOCKTIMEVERIFY OP_DROP
|
||||
OP_1 OP_CHECKSEQUENCEVERIFY`,
|
||||
txscript.WithScriptTemplateParams(TemplateParams{
|
||||
"Key": key.SerializeCompressed(),
|
||||
"LeaseExpiry": int64(leaseExpiry),
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
// CommitSpendToRemoteConfirmed constructs a valid witness allowing a node to
|
||||
@@ -2805,24 +2605,19 @@ func CommitSpendToRemoteConfirmed(signer Signer, signDesc *SignDescriptor,
|
||||
// OP_16 OP_CSV
|
||||
// OP_ENDIF
|
||||
func CommitScriptAnchor(key *btcec.PublicKey) ([]byte, error) {
|
||||
builder := txscript.NewScriptBuilder(txscript.WithScriptAllocSize(
|
||||
AnchorScriptSize,
|
||||
))
|
||||
|
||||
// Spend immediately with key.
|
||||
builder.AddData(key.SerializeCompressed())
|
||||
builder.AddOp(txscript.OP_CHECKSIG)
|
||||
|
||||
// Duplicate the value if true, since it will be consumed by the NOTIF.
|
||||
builder.AddOp(txscript.OP_IFDUP)
|
||||
|
||||
// Otherwise spendable by anyone after 16 confirmations.
|
||||
builder.AddOp(txscript.OP_NOTIF)
|
||||
builder.AddOp(txscript.OP_16)
|
||||
builder.AddOp(txscript.OP_CHECKSEQUENCEVERIFY)
|
||||
builder.AddOp(txscript.OP_ENDIF)
|
||||
|
||||
return builder.Script()
|
||||
// Build the anchor script with two possible spending paths:
|
||||
// 1. Spend immediately with key (the normal path)
|
||||
// 2. Spend after 16 confirmations by anyone (the alternative path)
|
||||
return txscript.ScriptTemplate(
|
||||
`
|
||||
{{ hex .Key }} OP_CHECKSIG OP_IFDUP
|
||||
OP_NOTIF
|
||||
OP_16 OP_CHECKSEQUENCEVERIFY
|
||||
OP_ENDIF`,
|
||||
txscript.WithScriptTemplateParams(TemplateParams{
|
||||
"Key": key.SerializeCompressed(),
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
// AnchorScriptTree holds all the contents needed to sweep a taproot anchor
|
||||
@@ -2841,11 +2636,9 @@ func NewAnchorScriptTree(
|
||||
|
||||
// The main script used is just a OP_16 CSV (anyone can sweep after 16
|
||||
// blocks).
|
||||
builder := txscript.NewScriptBuilder()
|
||||
builder.AddOp(txscript.OP_16)
|
||||
builder.AddOp(txscript.OP_CHECKSEQUENCEVERIFY)
|
||||
|
||||
anchorScript, err := builder.Script()
|
||||
anchorScript, err := txscript.ScriptTemplate(
|
||||
`OP_16 OP_CHECKSEQUENCEVERIFY`,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@@ -169,10 +169,10 @@ func TapscriptFullKeyOnly(taprootKey *btcec.PublicKey) *waddrmgr.Tapscript {
|
||||
// witness program. The passed public key will be serialized as an x-only key
|
||||
// to create the witness program.
|
||||
func PayToTaprootScript(taprootKey *btcec.PublicKey) ([]byte, error) {
|
||||
builder := txscript.NewScriptBuilder()
|
||||
|
||||
builder.AddOp(txscript.OP_1)
|
||||
builder.AddData(schnorr.SerializePubKey(taprootKey))
|
||||
|
||||
return builder.Script()
|
||||
return txscript.ScriptTemplate(
|
||||
`OP_1 {{ hex .TaprootKey }}`,
|
||||
txscript.WithScriptTemplateParams(TemplateParams{
|
||||
"TaprootKey": schnorr.SerializePubKey(taprootKey),
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
Reference in New Issue
Block a user