mirror of
https://github.com/btcsuite/btcd.git
synced 2024-11-19 01:40:07 +01:00
txscript: add tests for RawTxInTaprootSignature and RawTxInTapscriptSignature
In this commit, we add tests for the public functions used to generate keyspend and tapscript signatures. Without the prior commit, these tests will fail as the keyspend function won't properly add the sighash bytes for things that aren't sighash default.
This commit is contained in:
parent
5e0de1c539
commit
d6efaa7208
@ -10,10 +10,12 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/btcsuite/btcd/btcec/v2"
|
||||
"github.com/btcsuite/btcd/btcec/v2/schnorr"
|
||||
"github.com/btcsuite/btcd/btcutil"
|
||||
"github.com/btcsuite/btcd/chaincfg"
|
||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
type addressToKey struct {
|
||||
@ -1692,3 +1694,205 @@ nexttest:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestRawTxInTaprootSignature tests that the RawTxInTaprootSignature function
|
||||
// generates valid signatures for all relevant sighash types.
|
||||
func TestRawTxInTaprootSignature(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
privKey, err := btcec.NewPrivateKey()
|
||||
require.NoError(t, err)
|
||||
|
||||
pubKey := ComputeTaprootKeyNoScript(privKey.PubKey())
|
||||
|
||||
pkScript, err := PayToTaprootScript(pubKey)
|
||||
require.NoError(t, err)
|
||||
|
||||
// We'll reuse this simple transaction for the tests below. It ends up
|
||||
// spending from a bip86 P2TR output.
|
||||
testTx := wire.NewMsgTx(2)
|
||||
testTx.AddTxIn(&wire.TxIn{
|
||||
PreviousOutPoint: wire.OutPoint{
|
||||
Index: 1,
|
||||
},
|
||||
})
|
||||
txOut := &wire.TxOut{
|
||||
Value: 1e8, PkScript: pkScript,
|
||||
}
|
||||
testTx.AddTxOut(txOut)
|
||||
|
||||
tests := []struct {
|
||||
sigHashType SigHashType
|
||||
}{
|
||||
{
|
||||
sigHashType: SigHashDefault,
|
||||
},
|
||||
{
|
||||
sigHashType: SigHashAll,
|
||||
},
|
||||
{
|
||||
sigHashType: SigHashNone,
|
||||
},
|
||||
{
|
||||
sigHashType: SigHashSingle,
|
||||
},
|
||||
{
|
||||
sigHashType: SigHashSingle | SigHashAnyOneCanPay,
|
||||
},
|
||||
{
|
||||
sigHashType: SigHashNone | SigHashAnyOneCanPay,
|
||||
},
|
||||
{
|
||||
sigHashType: SigHashAll | SigHashAnyOneCanPay,
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
name := fmt.Sprintf("sighash=%v", test.sigHashType)
|
||||
t.Run(name, func(t *testing.T) {
|
||||
prevFetcher := NewCannedPrevOutputFetcher(
|
||||
txOut.PkScript, txOut.Value,
|
||||
)
|
||||
sigHashes := NewTxSigHashes(testTx, prevFetcher)
|
||||
|
||||
sig, err := RawTxInTaprootSignature(
|
||||
testTx, sigHashes, 0, txOut.Value, txOut.PkScript,
|
||||
nil, test.sigHashType, privKey,
|
||||
)
|
||||
require.NoError(t, err)
|
||||
|
||||
// If this isn't sighash default, then a sighash should be
|
||||
// applied. Otherwise, it should be a normal sig.
|
||||
expectedLen := schnorr.SignatureSize
|
||||
if test.sigHashType != SigHashDefault {
|
||||
expectedLen += 1
|
||||
}
|
||||
require.Len(t, sig, expectedLen)
|
||||
|
||||
// Finally, ensure that the signature produced is valid.
|
||||
txCopy := testTx.Copy()
|
||||
txCopy.TxIn[0].Witness = wire.TxWitness{sig}
|
||||
vm, err := NewEngine(
|
||||
txOut.PkScript, txCopy, 0, StandardVerifyFlags,
|
||||
nil, sigHashes, txOut.Value, prevFetcher,
|
||||
)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.NoError(t, vm.Execute())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestRawTxInTapscriptSignature thats that we're able to produce valid schnorr
|
||||
// signatures for a simple tapscript spend, for various sighash types.
|
||||
func TestRawTxInTapscriptSignature(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
privKey, err := btcec.NewPrivateKey()
|
||||
require.NoError(t, err)
|
||||
|
||||
internalKey := privKey.PubKey()
|
||||
|
||||
// Our script will be a simple OP_CHECKSIG as the sole leaf of a
|
||||
// tapscript tree. We'll also re-use the internal key as the key in the
|
||||
// leaf.
|
||||
builder := NewScriptBuilder()
|
||||
builder.AddData(schnorr.SerializePubKey(internalKey))
|
||||
builder.AddOp(OP_CHECKSIG)
|
||||
pkScript, err := builder.Script()
|
||||
require.NoError(t, err)
|
||||
|
||||
tapLeaf := NewBaseTapLeaf(pkScript)
|
||||
tapScriptTree := AssembleTaprootScriptTree(tapLeaf)
|
||||
|
||||
ctrlBlock := tapScriptTree.LeafMerkleProofs[0].ToControlBlock(
|
||||
internalKey,
|
||||
)
|
||||
|
||||
tapScriptRootHash := tapScriptTree.RootNode.TapHash()
|
||||
outputKey := ComputeTaprootOutputKey(
|
||||
internalKey, tapScriptRootHash[:],
|
||||
)
|
||||
p2trScript, err := PayToTaprootScript(outputKey)
|
||||
require.NoError(t, err)
|
||||
|
||||
// We'll reuse this simple transaction for the tests below. It ends up
|
||||
// spending from a bip86 P2TR output.
|
||||
testTx := wire.NewMsgTx(2)
|
||||
testTx.AddTxIn(&wire.TxIn{
|
||||
PreviousOutPoint: wire.OutPoint{
|
||||
Index: 1,
|
||||
},
|
||||
})
|
||||
txOut := &wire.TxOut{
|
||||
Value: 1e8, PkScript: p2trScript,
|
||||
}
|
||||
testTx.AddTxOut(txOut)
|
||||
|
||||
tests := []struct {
|
||||
sigHashType SigHashType
|
||||
}{
|
||||
{
|
||||
sigHashType: SigHashDefault,
|
||||
},
|
||||
{
|
||||
sigHashType: SigHashAll,
|
||||
},
|
||||
{
|
||||
sigHashType: SigHashNone,
|
||||
},
|
||||
{
|
||||
sigHashType: SigHashSingle,
|
||||
},
|
||||
{
|
||||
sigHashType: SigHashSingle | SigHashAnyOneCanPay,
|
||||
},
|
||||
{
|
||||
sigHashType: SigHashNone | SigHashAnyOneCanPay,
|
||||
},
|
||||
{
|
||||
sigHashType: SigHashAll | SigHashAnyOneCanPay,
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
name := fmt.Sprintf("sighash=%v", test.sigHashType)
|
||||
t.Run(name, func(t *testing.T) {
|
||||
prevFetcher := NewCannedPrevOutputFetcher(
|
||||
txOut.PkScript, txOut.Value,
|
||||
)
|
||||
sigHashes := NewTxSigHashes(testTx, prevFetcher)
|
||||
|
||||
sig, err := RawTxInTapscriptSignature(
|
||||
testTx, sigHashes, 0, txOut.Value,
|
||||
txOut.PkScript, tapLeaf, test.sigHashType,
|
||||
privKey,
|
||||
)
|
||||
require.NoError(t, err)
|
||||
|
||||
// If this isn't sighash default, then a sighash should
|
||||
// be applied. Otherwise, it should be a normal sig.
|
||||
expectedLen := schnorr.SignatureSize
|
||||
if test.sigHashType != SigHashDefault {
|
||||
expectedLen += 1
|
||||
}
|
||||
require.Len(t, sig, expectedLen)
|
||||
|
||||
// Now that we have the sig, we'll make a valid witness
|
||||
// including the control block.
|
||||
ctrlBlockBytes, err := ctrlBlock.ToBytes()
|
||||
require.NoError(t, err)
|
||||
txCopy := testTx.Copy()
|
||||
txCopy.TxIn[0].Witness = wire.TxWitness{
|
||||
sig, pkScript, ctrlBlockBytes,
|
||||
}
|
||||
|
||||
// Finally, ensure that the signature produced is valid.
|
||||
vm, err := NewEngine(
|
||||
txOut.PkScript, txCopy, 0, StandardVerifyFlags,
|
||||
nil, sigHashes, txOut.Value, prevFetcher,
|
||||
)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.NoError(t, vm.Execute())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user