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.
396 lines
13 KiB
Go
396 lines
13 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 (
|
|
"bytes"
|
|
"fmt"
|
|
"testing"
|
|
|
|
"github.com/decred/dcrd/txscript/v4"
|
|
)
|
|
|
|
// These variables are used to help ensure the benchmarks do not elide code.
|
|
var (
|
|
noElideSwapData *AtomicSwapDataPushesV0
|
|
)
|
|
|
|
// complexScriptV0 is a version 0 script comprised of half as many opcodes as
|
|
// the maximum allowed followed by as many max size data pushes fit without
|
|
// exceeding the max allowed script size.
|
|
var complexScriptV0 = func() []byte {
|
|
const (
|
|
maxScriptSize = txscript.MaxScriptSize
|
|
maxScriptElementSize = txscript.MaxScriptElementSize
|
|
)
|
|
var scriptLen int
|
|
builder := txscript.NewScriptBuilder()
|
|
for i := 0; i < txscript.MaxOpsPerScript/2; i++ {
|
|
builder.AddOp(txscript.OP_TRUE)
|
|
scriptLen++
|
|
}
|
|
maxData := bytes.Repeat([]byte{0x02}, maxScriptElementSize)
|
|
for i := 0; i < (maxScriptSize-scriptLen)/maxScriptElementSize; i++ {
|
|
builder.AddData(maxData)
|
|
}
|
|
script, err := builder.Script()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
return script
|
|
}()
|
|
|
|
// makeBenchmarks constructs a slice of tests to use in the benchmarks as
|
|
// follows:
|
|
// - Start with a version 0 complex non standard script
|
|
// - Add all tests for which the provided filter function returns true
|
|
func makeBenchmarks(filterFn func(test scriptTest) bool) []scriptTest {
|
|
benches := make([]scriptTest, 0, 5)
|
|
benches = append(benches, scriptTest{
|
|
name: "v0 complex non standard",
|
|
version: 0,
|
|
script: complexScriptV0,
|
|
})
|
|
for _, test := range scriptV0Tests {
|
|
if filterFn(test) {
|
|
benches = append(benches, test)
|
|
}
|
|
}
|
|
return benches
|
|
}
|
|
|
|
// benchIsX is a convenience function that runs benchmarks for the entries that
|
|
// match the provided filter function using the given script type determination
|
|
// function and ensures the result matches the expected one.
|
|
func benchIsX(b *testing.B, filterFn func(test scriptTest) bool, isXFn func(scriptVersion uint16, script []byte) bool) {
|
|
b.Helper()
|
|
|
|
benches := makeBenchmarks(filterFn)
|
|
for _, bench := range benches {
|
|
want := filterFn(bench)
|
|
b.Run(bench.name, func(b *testing.B) {
|
|
b.ReportAllocs()
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
got := isXFn(bench.version, bench.script)
|
|
if got != want {
|
|
b.Fatalf("%q: unexpected result -- got %v, want %v",
|
|
bench.name, got, want)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// BenchmarkIsPubKeyScript benchmarks the performance of analyzing various
|
|
// public key scripts to determine if they are p2pk-ecdsa-secp256k1 scripts.
|
|
func BenchmarkIsPubKeyScript(b *testing.B) {
|
|
filterFn := func(test scriptTest) bool {
|
|
return test.wantType == STPubKeyEcdsaSecp256k1
|
|
}
|
|
benchIsX(b, filterFn, IsPubKeyScript)
|
|
}
|
|
|
|
// BenchmarkIsPubKeyEd25519Script benchmarks the performance of analyzing
|
|
// various public key scripts to determine if they are p2pkh-ed25519 scripts.
|
|
func BenchmarkIsPubKeyEd25519Script(b *testing.B) {
|
|
filterFn := func(test scriptTest) bool {
|
|
return test.wantType == STPubKeyEd25519
|
|
}
|
|
benchIsX(b, filterFn, IsPubKeyEd25519Script)
|
|
}
|
|
|
|
// BenchmarkIsPubKeySchnorrSecp256k1Script benchmarks the performance of
|
|
// analyzing various public key scripts to determine if they are
|
|
// p2pkh-schnorr-secp256k1 scripts.
|
|
func BenchmarkIsPubKeySchnorrSecp256k1Script(b *testing.B) {
|
|
filterFn := func(test scriptTest) bool {
|
|
return test.wantType == STPubKeySchnorrSecp256k1
|
|
}
|
|
benchIsX(b, filterFn, IsPubKeySchnorrSecp256k1Script)
|
|
}
|
|
|
|
// BenchmarkIsPubKeyHashScript benchmarks the performance of analyzing various
|
|
// public key scripts to determine if they are p2pkh-ecdsa-secp256k1 scripts.
|
|
func BenchmarkIsPubKeyHashScript(b *testing.B) {
|
|
filterFn := func(test scriptTest) bool {
|
|
return test.wantType == STPubKeyHashEcdsaSecp256k1
|
|
}
|
|
benchIsX(b, filterFn, IsPubKeyHashScript)
|
|
}
|
|
|
|
// BenchmarkIsPubKeyHashEd25519Script benchmarks the performance of analyzing
|
|
// various public key scripts to determine if they are p2pkh-ed25519 scripts.
|
|
func BenchmarkIsPubKeyHashEd25519Script(b *testing.B) {
|
|
filterFn := func(test scriptTest) bool {
|
|
return test.wantType == STPubKeyHashEd25519
|
|
}
|
|
benchIsX(b, filterFn, IsPubKeyHashEd25519Script)
|
|
}
|
|
|
|
// BenchmarkIsPubKeyHashSchnorrSecp256k1Script benchmarks the performance of
|
|
// analyzing various public key scripts to determine if they are
|
|
// p2pkh-schnorr-secp256k1 scripts.
|
|
func BenchmarkIsPubKeyHashSchnorrSecp256k1Script(b *testing.B) {
|
|
filterFn := func(test scriptTest) bool {
|
|
return test.wantType == STPubKeyHashSchnorrSecp256k1
|
|
}
|
|
benchIsX(b, filterFn, IsPubKeyHashSchnorrSecp256k1Script)
|
|
}
|
|
|
|
// BenchmarkIsScriptHashScript benchmarks the performance of analyzing various
|
|
// public key scripts to determine if they are p2sh scripts.
|
|
func BenchmarkIsScriptHashScript(b *testing.B) {
|
|
filterFn := func(test scriptTest) bool {
|
|
return test.wantType == STScriptHash
|
|
}
|
|
benchIsX(b, filterFn, IsScriptHashScript)
|
|
}
|
|
|
|
// BenchmarkIsMultiSigScript benchmarks the performance of analyzing various
|
|
// public key scripts to determine if they are multisignature scripts.
|
|
func BenchmarkIsMultiSigScript(b *testing.B) {
|
|
filterFn := func(test scriptTest) bool {
|
|
return test.wantType == STMultiSig && !test.isSig
|
|
}
|
|
benchIsX(b, filterFn, IsMultiSigScript)
|
|
}
|
|
|
|
// BenchmarkIsMultiSigSigScript benchmarks the performance of analyzing various
|
|
// signature scripts to determine if they are likely to be multisignature redeem
|
|
// scripts.
|
|
func BenchmarkIsMultiSigSigScript(b *testing.B) {
|
|
filterFn := func(test scriptTest) bool {
|
|
return test.wantType == STMultiSig && test.isSig
|
|
}
|
|
benchIsX(b, filterFn, IsMultiSigSigScript)
|
|
}
|
|
|
|
// BenchmarkMultiSigRedeemScriptFromScriptSigV0 benchmarks the performance of
|
|
// extracting the redeem script from various version 0 signature scripts.
|
|
func BenchmarkMultiSigRedeemScriptFromScriptSigV0(b *testing.B) {
|
|
for _, test := range scriptV0Tests {
|
|
if test.version != 0 || test.wantType != STMultiSig || !test.isSig {
|
|
continue
|
|
}
|
|
want := test.wantData.([]byte)
|
|
|
|
b.Run(test.name, func(b *testing.B) {
|
|
b.ReportAllocs()
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
got := MultiSigRedeemScriptFromScriptSigV0(test.script)
|
|
if !bytes.Equal(got, want) {
|
|
b.Fatalf("%q: unexpected result -- got %x, want %x",
|
|
test.name, got, want)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// BenchmarkIsNullDataScript benchmarks the performance of analyzing various
|
|
// public key scripts to determine if they are nulldata scripts.
|
|
func BenchmarkIsNullDataScript(b *testing.B) {
|
|
filterFn := func(test scriptTest) bool {
|
|
return test.wantType == STNullData
|
|
}
|
|
benchIsX(b, filterFn, IsNullDataScript)
|
|
}
|
|
|
|
// BenchmarkIsStakeSubmissionPubKeyHashScript benchmarks the performance of
|
|
// analyzing various public key scripts to determine if they are stake
|
|
// submission p2pkh-ecdsa-secp256k1 scripts.
|
|
func BenchmarkIsStakeSubmissionPubKeyHashScript(b *testing.B) {
|
|
filterFn := func(test scriptTest) bool {
|
|
return test.wantType == STStakeSubmissionPubKeyHash
|
|
}
|
|
benchIsX(b, filterFn, IsStakeSubmissionPubKeyHashScript)
|
|
}
|
|
|
|
// BenchmarkIsStakeSubmissionScriptHashScript benchmarks the performance of
|
|
// analyzing various public key scripts to determine if they are stake
|
|
// submission p2sh scripts.
|
|
func BenchmarkIsStakeSubmissionScriptHashScript(b *testing.B) {
|
|
filterFn := func(test scriptTest) bool {
|
|
return test.wantType == STStakeSubmissionScriptHash
|
|
}
|
|
benchIsX(b, filterFn, IsStakeSubmissionScriptHashScript)
|
|
}
|
|
|
|
// BenchmarkIsStakeGenPubKeyHashScript benchmarks the performance of analyzing
|
|
// various public key scripts to determine if they are stake generation
|
|
// p2pkh-ecdsa-secp256k1 scripts.
|
|
func BenchmarkIsStakeGenPubKeyHashScript(b *testing.B) {
|
|
filterFn := func(test scriptTest) bool {
|
|
return test.wantType == STStakeGenPubKeyHash
|
|
}
|
|
benchIsX(b, filterFn, IsStakeGenPubKeyHashScript)
|
|
}
|
|
|
|
// BenchmarkIsStakeGenScriptHashScript benchmarks the performance of analyzing various
|
|
// public key scripts to determine if they are stake generation p2sh scripts.
|
|
func BenchmarkIsStakeGenScriptHashScript(b *testing.B) {
|
|
filterFn := func(test scriptTest) bool {
|
|
return test.wantType == STStakeGenScriptHash
|
|
}
|
|
benchIsX(b, filterFn, IsStakeGenScriptHashScript)
|
|
}
|
|
|
|
// BenchmarkIsStakeRevocationPubKeyHashScript benchmarks the performance of
|
|
// analyzing various public key scripts to determine if they are stake
|
|
// revocation p2pkh-ecdsa-secp256k1 scripts.
|
|
func BenchmarkIsStakeRevocationPubKeyHashScript(b *testing.B) {
|
|
filterFn := func(test scriptTest) bool {
|
|
return test.wantType == STStakeRevocationPubKeyHash
|
|
}
|
|
benchIsX(b, filterFn, IsStakeRevocationPubKeyHashScript)
|
|
}
|
|
|
|
// BenchmarkIsStakeRevocationScriptHashScript benchmarks the performance of
|
|
// various public key scripts to determine if they are stake revocation p2sh
|
|
// scripts.
|
|
func BenchmarkIsStakeRevocationScriptHashScript(b *testing.B) {
|
|
filterFn := func(test scriptTest) bool {
|
|
return test.wantType == STStakeRevocationScriptHash
|
|
}
|
|
benchIsX(b, filterFn, IsStakeRevocationScriptHashScript)
|
|
}
|
|
|
|
// BenchmarkIsStakeChangePubKeyHash benchmarks the performance of analyzing
|
|
// various public key scripts to determine if they are stake change
|
|
// p2pkh-ecdsa-secp256k1 scripts.
|
|
func BenchmarkIsStakeChangePubKeyHash(b *testing.B) {
|
|
filterFn := func(test scriptTest) bool {
|
|
return test.wantType == STStakeChangePubKeyHash
|
|
}
|
|
benchIsX(b, filterFn, IsStakeChangePubKeyHashScript)
|
|
}
|
|
|
|
// BenchmarkIsStakeChangeScriptHash benchmarks the performance of analyzing
|
|
// various public key scripts to determine if they are stake change p2sh
|
|
// scripts.
|
|
func BenchmarkIsStakeChangeScriptHash(b *testing.B) {
|
|
filterFn := func(test scriptTest) bool {
|
|
return test.wantType == STStakeChangeScriptHash
|
|
}
|
|
benchIsX(b, filterFn, IsStakeChangeScriptHashScript)
|
|
}
|
|
|
|
// BenchmarkIsTreasuryAddScript benchmarks the performance of analyzing various
|
|
// public key scripts to determine if they are treasury add scripts.
|
|
func BenchmarkIsTreasuryAddScript(b *testing.B) {
|
|
filterFn := func(test scriptTest) bool {
|
|
return test.wantType == STTreasuryAdd
|
|
}
|
|
benchIsX(b, filterFn, IsTreasuryAddScript)
|
|
}
|
|
|
|
// BenchmarkIsTreasuryGenPubKeyHashScript benchmarks the performance of
|
|
// analyzing various public key scripts to determine if they are treasury
|
|
// generation p2pkh-ecdsa-secp256k1 scripts.
|
|
func BenchmarkIsTreasuryGenPubKeyHashScript(b *testing.B) {
|
|
filterFn := func(test scriptTest) bool {
|
|
return test.wantType == STTreasuryGenPubKeyHash
|
|
}
|
|
benchIsX(b, filterFn, IsTreasuryGenPubKeyHashScript)
|
|
}
|
|
|
|
// BenchmarkIsTreasuryGenScriptHashScript benchmarks the performance of
|
|
// analyzing various public key scripts to determine if they are treasury
|
|
// generation p2sh scripts.
|
|
func BenchmarkIsTreasuryGenScriptHashScript(b *testing.B) {
|
|
filterFn := func(test scriptTest) bool {
|
|
return test.wantType == STTreasuryGenScriptHash
|
|
}
|
|
benchIsX(b, filterFn, IsTreasuryGenScriptHashScript)
|
|
}
|
|
|
|
// BenchmarkDetermineScriptType benchmarks the performance of analyzing various
|
|
// public key scripts to determine what type of standard script they are.
|
|
func BenchmarkDetermineScriptType(b *testing.B) {
|
|
counts := make(map[ScriptType]int)
|
|
benches := makeBenchmarks(func(test scriptTest) bool {
|
|
// Limit to one of each script type.
|
|
counts[test.wantType]++
|
|
return test.wantType != STNonStandard && counts[test.wantType] == 1
|
|
})
|
|
|
|
for _, bench := range benches {
|
|
b.Run(bench.name, func(b *testing.B) {
|
|
b.ReportAllocs()
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
got := DetermineScriptType(bench.version, bench.script)
|
|
if got != bench.wantType {
|
|
b.Fatalf("%q: unexpected result -- got %v, want %v",
|
|
bench.name, got, bench.wantType)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// BenchmarkDetermineRequiredSigs benchmarks the performance of determining the
|
|
// required number of signatures for various public key scripts.
|
|
func BenchmarkDetermineRequiredSigs(b *testing.B) {
|
|
counts := make(map[ScriptType]int)
|
|
benches := makeBenchmarks(func(test scriptTest) bool {
|
|
// Limit to one of each script type.
|
|
counts[test.wantType]++
|
|
return counts[test.wantType] == 1
|
|
})
|
|
|
|
for _, bench := range benches {
|
|
b.Run(bench.name, func(b *testing.B) {
|
|
b.ReportAllocs()
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
got := DetermineRequiredSigs(bench.version, bench.script)
|
|
if got != bench.wantSigs {
|
|
b.Fatalf("%q: unexpected result -- got %v, want %v",
|
|
bench.name, got, bench.wantSigs)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// BenchmarkExtractAtomicSwapDataPushes benchmarks the performance of
|
|
// attempting to extract the atomic swap data pushes from various version 0
|
|
// public key scripts.
|
|
func BenchmarkExtractAtomicSwapDataPushes(b *testing.B) {
|
|
benches := []struct {
|
|
name string // benchmark name
|
|
script []byte // script to analyze
|
|
}{{
|
|
name: "v0 complex not atomic swap",
|
|
script: complexScriptV0,
|
|
}, {
|
|
name: "v0 normal valid atomic swap",
|
|
script: mustParseShortForm(0, fmt.Sprintf("IF "+
|
|
"SIZE 32 EQUALVERIFY "+
|
|
"SHA256 DATA_32 "+
|
|
"0x9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08 "+
|
|
"EQUALVERIFY DUP HASH160 "+
|
|
"DATA_20 0x0000000000000000000000000000000000000001 "+
|
|
"ELSE "+
|
|
"300000 CHECKLOCKTIMEVERIFY DROP DUP HASH160 "+
|
|
"DATA_20 0x0000000000000000000000000000000000000002 "+
|
|
"ENDIF "+
|
|
"EQUALVERIFY CHECKSIG")),
|
|
}}
|
|
|
|
for _, bench := range benches {
|
|
b.Run(bench.name, func(b *testing.B) {
|
|
b.ReportAllocs()
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
noElideSwapData = ExtractAtomicSwapDataPushesV0(bench.script)
|
|
}
|
|
})
|
|
}
|
|
}
|