This moves the new stdscript package from the internal staging area to the txscript module and updates the relevant paths and package README.md accordingly.
223 lines
8.2 KiB
Go
223 lines
8.2 KiB
Go
// Copyright (c) 2021 The Decred developers
|
|
// Use of this source code is governed by an ISC
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package stdscript
|
|
|
|
import (
|
|
"testing"
|
|
)
|
|
|
|
// TestScriptTypeStringer tests the stringized output for the ScriptType type.
|
|
func TestScriptTypeStringer(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
tests := []struct {
|
|
in ScriptType
|
|
want string
|
|
}{
|
|
{STNonStandard, "nonstandard"},
|
|
{STPubKeyEcdsaSecp256k1, "pubkey"},
|
|
{STPubKeyEd25519, "pubkey-ed25519"},
|
|
{STPubKeySchnorrSecp256k1, "pubkey-schnorr-secp256k1"},
|
|
{STPubKeyHashEcdsaSecp256k1, "pubkeyhash"},
|
|
{STPubKeyHashEd25519, "pubkeyhash-ed25519"},
|
|
{STPubKeyHashSchnorrSecp256k1, "pubkeyhash-schnorr-secp256k1"},
|
|
{STScriptHash, "scripthash"},
|
|
{STMultiSig, "multisig"},
|
|
{STNullData, "nulldata"},
|
|
{STStakeSubmissionPubKeyHash, "stakesubmission-pubkeyhash"},
|
|
{STStakeSubmissionScriptHash, "stakesubmission-scripthash"},
|
|
{STStakeGenPubKeyHash, "stakegen-pubkeyhash"},
|
|
{STStakeGenScriptHash, "stakegen-scripthash"},
|
|
{STStakeRevocationPubKeyHash, "stakerevoke-pubkeyhash"},
|
|
{STStakeRevocationScriptHash, "stakerevoke-scripthash"},
|
|
{STStakeChangePubKeyHash, "stakechange-pubkeyhash"},
|
|
{STStakeChangeScriptHash, "stakechange-scripthash"},
|
|
{STTreasuryAdd, "treasuryadd"},
|
|
{STTreasuryGenPubKeyHash, "treasurygen-pubkeyhash"},
|
|
{STTreasuryGenScriptHash, "treasurygen-scripthash"},
|
|
{0xff, "invalid"},
|
|
}
|
|
|
|
// Detect additional error codes that don't have the stringer added.
|
|
if len(tests)-1 != int(numScriptTypes) {
|
|
t.Error("It appears a script type was added without adding an " +
|
|
"associated stringer test")
|
|
}
|
|
|
|
for _, test := range tests {
|
|
result := test.in.String()
|
|
if result != test.want {
|
|
t.Errorf("%q: unexpected string -- got: %s", test.want, result)
|
|
continue
|
|
}
|
|
}
|
|
}
|
|
|
|
// scriptTest describes tests for scripts that are used to ensure various script
|
|
// types and data extraction is working as expected. It's defined separately
|
|
// since it is intended for use in multiple shared per-version tests.
|
|
type scriptTest struct {
|
|
name string // test description
|
|
version uint16 // version of script to analyze
|
|
script []byte // script to analyze
|
|
isSig bool // treat as a signature script instead
|
|
wantType ScriptType // expected script type
|
|
wantData interface{} // expected extracted data when applicable
|
|
wantSigs uint16 // expected number of required signatures
|
|
}
|
|
|
|
// TestDetermineScriptType ensures a wide variety of scripts for various script
|
|
// versions are identified with the expected script type.
|
|
func TestDetermineScriptType(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
// Specify the per-version tests to include in the overall tests here.
|
|
// This is done to make it easy to add independent tests for new script
|
|
// versions while still testing them all through the API that accepts a
|
|
// specific version versus the exported variant that is specific to a given
|
|
// version per its exported name.
|
|
//
|
|
// NOTE: Maintainers should add tests for new script versions following the
|
|
// way scriptV0Tests is handled and add the resulting per-version tests
|
|
// here.
|
|
perVersionTests := [][]scriptTest{
|
|
scriptV0Tests,
|
|
}
|
|
|
|
// Flatten all of the per-version tests into a single set of tests.
|
|
var tests []scriptTest
|
|
for _, bundle := range perVersionTests {
|
|
tests = append(tests, bundle...)
|
|
}
|
|
|
|
for _, test := range tests {
|
|
// Ensure that the script is considered non standard for unsupported
|
|
// script versions regardless.
|
|
const unsupportedScriptVer = 9999
|
|
gotType := DetermineScriptType(unsupportedScriptVer, test.script)
|
|
if gotType != STNonStandard {
|
|
t.Errorf("%q -- unsupported script version: mismatched type -- "+
|
|
"got %s, want %s (script %x)", test.name, gotType,
|
|
STNonStandard, test.script)
|
|
continue
|
|
}
|
|
|
|
// Ensure the overall type determination produces the expected result.
|
|
gotType = DetermineScriptType(test.version, test.script)
|
|
if !test.isSig && gotType != test.wantType {
|
|
t.Errorf("%q: mismatched type -- got %s, want %s (script %x)",
|
|
test.name, gotType, test.wantType, test.script)
|
|
continue
|
|
}
|
|
|
|
// These are convenience helpers to ensure a given individual script
|
|
// type determination function matches the expected result per the given
|
|
// desired type.
|
|
type isXFn func(scriptVersion uint16, script []byte) bool
|
|
testIsXInternal := func(fn isXFn, isSig bool, wantType ScriptType) {
|
|
t.Helper()
|
|
|
|
// Ensure that the script is considered non standard for unsupported
|
|
// script versions regardless.
|
|
got := fn(unsupportedScriptVer, test.script)
|
|
if got {
|
|
t.Errorf("%q -- unsupported script version return true "+
|
|
"(script %x)", test.name, test.script)
|
|
return
|
|
}
|
|
|
|
got = fn(test.version, test.script)
|
|
want := test.isSig == isSig && test.wantType == wantType
|
|
if got != want {
|
|
t.Errorf("%q: mismatched is func %v -- got %v, want %v "+
|
|
"(script %x)", test.name, wantType, got, want, test.script)
|
|
}
|
|
}
|
|
testIsX := func(fn isXFn, wantType ScriptType) {
|
|
t.Helper()
|
|
testIsXInternal(fn, false, wantType)
|
|
}
|
|
testIsSigX := func(fn isXFn, wantType ScriptType) {
|
|
t.Helper()
|
|
testIsXInternal(fn, true, wantType)
|
|
}
|
|
|
|
// Ensure the individual determination methods produce the expected
|
|
// results.
|
|
testIsX(IsPubKeyScript, STPubKeyEcdsaSecp256k1)
|
|
testIsX(IsPubKeyEd25519Script, STPubKeyEd25519)
|
|
testIsX(IsPubKeySchnorrSecp256k1Script, STPubKeySchnorrSecp256k1)
|
|
testIsX(IsPubKeyHashScript, STPubKeyHashEcdsaSecp256k1)
|
|
testIsX(IsPubKeyHashEd25519Script, STPubKeyHashEd25519)
|
|
testIsX(IsPubKeyHashSchnorrSecp256k1Script, STPubKeyHashSchnorrSecp256k1)
|
|
testIsX(IsScriptHashScript, STScriptHash)
|
|
testIsX(IsMultiSigScript, STMultiSig)
|
|
testIsX(IsNullDataScript, STNullData)
|
|
testIsX(IsStakeSubmissionPubKeyHashScript, STStakeSubmissionPubKeyHash)
|
|
testIsX(IsStakeSubmissionScriptHashScript, STStakeSubmissionScriptHash)
|
|
testIsX(IsStakeGenPubKeyHashScript, STStakeGenPubKeyHash)
|
|
testIsX(IsStakeGenScriptHashScript, STStakeGenScriptHash)
|
|
testIsX(IsStakeRevocationPubKeyHashScript, STStakeRevocationPubKeyHash)
|
|
testIsX(IsStakeRevocationScriptHashScript, STStakeRevocationScriptHash)
|
|
testIsX(IsStakeChangePubKeyHashScript, STStakeChangePubKeyHash)
|
|
testIsX(IsStakeChangeScriptHashScript, STStakeChangeScriptHash)
|
|
testIsX(IsTreasuryAddScript, STTreasuryAdd)
|
|
testIsX(IsTreasuryGenPubKeyHashScript, STTreasuryGenPubKeyHash)
|
|
testIsX(IsTreasuryGenScriptHashScript, STTreasuryGenScriptHash)
|
|
|
|
// Ensure the special case of determining if a signature script appears
|
|
// to be a signature script which consists of a pay-to-script-hash
|
|
// multi-signature redeem script.
|
|
testIsSigX(IsMultiSigSigScript, STMultiSig)
|
|
}
|
|
}
|
|
|
|
// TestDetermineRequiredSigs ensures a wide variety of scripts for various
|
|
// script versions return the expected number of required signatures.
|
|
func TestDetermineRequiredSigs(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
// Specify the per-version tests to include in the overall tests here.
|
|
// This is done to make it easy to add independent tests for new script
|
|
// versions while still testing them all through the API that accepts a
|
|
// specific version versus the exported variant that is specific to a given
|
|
// version per its exported name.
|
|
//
|
|
// NOTE: Maintainers should add tests for new script versions following the
|
|
// way scriptV0Tests is handled and add the resulting per-version tests
|
|
// here.
|
|
perVersionTests := [][]scriptTest{
|
|
scriptV0Tests,
|
|
}
|
|
|
|
// Flatten all of the per-version tests into a single set of tests.
|
|
var tests []scriptTest
|
|
for _, bundle := range perVersionTests {
|
|
tests = append(tests, bundle...)
|
|
}
|
|
|
|
for _, test := range tests {
|
|
// Ensure that no signatures are required for unsupported script
|
|
// versions regardless.
|
|
const unsupportedScriptVer = 9999
|
|
gotReqSigs := DetermineRequiredSigs(unsupportedScriptVer, test.script)
|
|
if gotReqSigs != 0 {
|
|
t.Errorf("%q -- unsupported script version: mismatched required "+
|
|
"sigs -- got %d, want %d (script %x)", test.name, gotReqSigs,
|
|
0, test.script)
|
|
continue
|
|
}
|
|
|
|
// Ensure that the calculated required number of signatures matches the
|
|
// expected result.
|
|
gotReqSigs = DetermineRequiredSigs(test.version, test.script)
|
|
if !test.isSig && gotReqSigs != test.wantSigs {
|
|
t.Errorf("%q: mismatched required sigs -- got %d, want %d "+
|
|
"(script %x)", test.name, gotReqSigs, test.wantSigs, test.script)
|
|
continue
|
|
}
|
|
}
|
|
}
|