This adds support for directly extracting the script hash from standard version 0 stake-tagged pay-to-script-hash scripts along with full test coverage. While all of this data can be extracted from each individual type, it can be more convenient for callers who treat all script hashes as the same entity which is the case for many applications.
1640 lines
57 KiB
Go
1640 lines
57 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"
|
|
"encoding/hex"
|
|
"errors"
|
|
"fmt"
|
|
"reflect"
|
|
"testing"
|
|
|
|
"github.com/decred/dcrd/dcrec"
|
|
)
|
|
|
|
// hexToBytes converts the passed hex string into bytes and will panic if there
|
|
// is an error. This is only provided for the hard-coded constants so errors in
|
|
// the source code can be detected. It will only (and must only) be called with
|
|
// hard-coded values.
|
|
func hexToBytes(s string) []byte {
|
|
b, err := hex.DecodeString(s)
|
|
if err != nil {
|
|
panic("invalid hex in source file: " + s)
|
|
}
|
|
return b
|
|
}
|
|
|
|
// scriptV0Tests houses several version 0 test scripts used to ensure various
|
|
// script types and data extraction is working as expected. It's defined as a
|
|
// test global versus inside a specific test function scope since it spans
|
|
// multiple tests and benchmarks.
|
|
var scriptV0Tests = func() []scriptTest {
|
|
// Convenience function that combines fmt.Sprintf with mustParseShortForm
|
|
// to create more compact tests.
|
|
p := func(format string, a ...interface{}) []byte {
|
|
const scriptVersion = 0
|
|
return mustParseShortForm(scriptVersion, fmt.Sprintf(format, a...))
|
|
}
|
|
|
|
// ---------------------------------------------------------------------
|
|
// Define some data shared in the tests for convenience.
|
|
// ---------------------------------------------------------------------
|
|
|
|
// Uncompressed and compressed/hybrid even/odd secp256k1 public keys along
|
|
// with hash160s of the compressed even ones.
|
|
pkUE := "0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f817" +
|
|
"98483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8"
|
|
pkUO := "04fff97bd5755eeea420453a14355235d382f6472f8568a18b2f057a14602975" +
|
|
"56ae12777aacfbb620f3be96017f45c560de80f0f6518fe4a03c870c36b075f297"
|
|
pkCE := "02" + pkUE[2:66]
|
|
h160CE := "e280cb6e66b96679aec288b1fbdbd4db08077a1b"
|
|
pkCE2 := "02f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9"
|
|
h160CE2 := "01557763e0252dc0ff9e0996ad1d04b167bb993c"
|
|
pkCO := "03" + pkUO[2:66]
|
|
pkHE := "05" + pkUE[2:]
|
|
pkHO := "06" + pkUO[2:]
|
|
|
|
// Ed25519 public key and hash.
|
|
pkEd := "cecc1507dc1ddd7295951c290888f095adb9044d1b73d696e6df065d683bd4fc"
|
|
h160Ed := "456d8ee57a4b9121987b4ecab8c3bcb5797e8a53"
|
|
|
|
// Script hash for a 2-of-3 multisig composed of pkCE, pkCE2, and pkCO.
|
|
p2sh := "f86b5a7c6d32566aa4dccc04d1533530b4d64cf3"
|
|
|
|
return []scriptTest{{
|
|
// ---------------------------------------------------------------------
|
|
// Misc negative tests.
|
|
// ---------------------------------------------------------------------
|
|
|
|
name: "malformed v0 script that does not parse",
|
|
script: p("DATA_5 0x01020304"),
|
|
wantType: STNonStandard,
|
|
}, {
|
|
name: "empty v0 script",
|
|
script: nil,
|
|
wantType: STNonStandard,
|
|
}, {
|
|
// ---------------------------------------------------------------------
|
|
// Negative P2PK ECDSA secp256k1 tests.
|
|
// ---------------------------------------------------------------------
|
|
|
|
name: "v0 p2pk-ecdsa-secp256k1 hybrid odd",
|
|
script: p("DATA_33 0x%s CHECKSIG", pkHO),
|
|
wantType: STNonStandard,
|
|
}, {
|
|
name: "v0 p2pk-ecdsa-secp256k1 hybrid even",
|
|
script: p("DATA_33 0x%s CHECKSIG", pkHE),
|
|
wantType: STNonStandard,
|
|
}, {
|
|
name: "almost v0 p2pk-ecdsa-secp256k1 -- trailing opcode",
|
|
script: p("DATA_33 0x%s CHECKSIG TRUE", pkCE),
|
|
wantType: STNonStandard,
|
|
}, {
|
|
name: "almost v0 p2pk-ecdsa-secp256k1 -- pubkey not pushed",
|
|
script: p("0x%s CHECKSIG", pkCE),
|
|
wantType: STNonStandard,
|
|
}, {
|
|
name: "almost v0 p2pk-ecdsa-secp256k1 -- malformed pubkey prefix",
|
|
script: p("DATA_33 0x08%s CHECKSIG", pkCE[2:]),
|
|
wantType: STNonStandard,
|
|
}, {
|
|
// ---------------------------------------------------------------------
|
|
// Positive P2PK ECDSA secp256k1 tests.
|
|
// ---------------------------------------------------------------------
|
|
|
|
name: "v0 p2pk-ecdsa-secp256k1 uncompressed",
|
|
script: p("DATA_65 0x%s CHECKSIG", pkUE),
|
|
wantType: STPubKeyEcdsaSecp256k1,
|
|
wantData: hexToBytes(pkUE),
|
|
wantSigs: 1,
|
|
}, {
|
|
name: "v0 p2pk-ecdsa-secp256k1 compressed even",
|
|
script: p("DATA_33 0x%s CHECKSIG", pkCE),
|
|
wantType: STPubKeyEcdsaSecp256k1,
|
|
wantData: hexToBytes(pkCE),
|
|
wantSigs: 1,
|
|
}, {
|
|
name: "v0 p2pk-ecdsa-secp256k1 compressed odd",
|
|
script: p("DATA_33 0x%s CHECKSIG", pkCO),
|
|
wantType: STPubKeyEcdsaSecp256k1,
|
|
wantData: hexToBytes(pkCO),
|
|
wantSigs: 1,
|
|
}, {
|
|
// ---------------------------------------------------------------------
|
|
// Negative P2PK Alt tests.
|
|
// ---------------------------------------------------------------------
|
|
|
|
name: "v0 p2pk-alt unsupported signature type 0",
|
|
script: p("DATA_33 0x%s 0 CHECKSIGALT", pkCE),
|
|
wantType: STNonStandard,
|
|
}, {
|
|
name: "v0 p2pk-alt unsupported signature type 3",
|
|
script: p("DATA_33 0x%s 3 CHECKSIGALT", pkCE),
|
|
wantType: STNonStandard,
|
|
}, {
|
|
name: "almost v0 p2pk-alt -- signature type not small int",
|
|
script: p("DATA_33 0x%s DATA_1 2 CHECKSIGALT", pkCE),
|
|
wantType: STNonStandard,
|
|
}, {
|
|
name: "almost v0 p2pk-alt -- NOP for signature type",
|
|
script: p("DATA_33 0x%s NOP CHECKSIGALT", pkCE),
|
|
wantType: STNonStandard,
|
|
}, {
|
|
// ---------------------------------------------------------------------
|
|
// Negative P2PK Ed25519 tests.
|
|
// ---------------------------------------------------------------------
|
|
|
|
name: "almost v0 p2pk-ed25519 -- trailing opcode",
|
|
script: p("DATA_32 0x%s 1 CHECKSIGALT TRUE", pkEd),
|
|
wantType: STNonStandard,
|
|
}, {
|
|
name: "almost v0 p2pk-ed25519 -- pubkey not pushed",
|
|
script: p("0x%s 1 CHECKSIGALT", pkEd),
|
|
wantType: STNonStandard,
|
|
}, {
|
|
name: "almost v0 p2pk-ed25519 -- wrong signature type",
|
|
script: p("DATA_32 0x%s 2 CHECKSIGALT", pkEd),
|
|
wantType: STNonStandard,
|
|
}, {
|
|
// ---------------------------------------------------------------------
|
|
// Positive P2PK Ed25519 tests.
|
|
// ---------------------------------------------------------------------
|
|
|
|
name: "v0 p2pk-ed25519",
|
|
script: p("DATA_32 0x%s 1 CHECKSIGALT", pkEd),
|
|
wantType: STPubKeyEd25519,
|
|
wantData: hexToBytes(pkEd),
|
|
wantSigs: 1,
|
|
}, {
|
|
// ---------------------------------------------------------------------
|
|
// Negative P2PK Schnorr secp256k1 tests.
|
|
// ---------------------------------------------------------------------
|
|
|
|
name: "v0 p2pk-schnorr-secp256k1 uncompressed",
|
|
script: p("DATA_65 0x%s 2 CHECKSIGALT", pkUE),
|
|
wantType: STNonStandard,
|
|
}, {
|
|
name: "v0 p2pk-schnorr-secp256k1 hybrid odd",
|
|
script: p("DATA_65 0x%s 2 CHECKSIGALT", pkHO),
|
|
wantType: STNonStandard,
|
|
}, {
|
|
name: "v0 p2pk-schnorr-secp256k1 hybrid even",
|
|
script: p("DATA_65 0x%s 2 CHECKSIGALT", pkHE),
|
|
wantType: STNonStandard,
|
|
}, {
|
|
name: "almost v0 p2pk-schnorr-secp256k1 -- trailing opcode",
|
|
script: p("DATA_33 0x%s 2 CHECKSIGALT TRUE", pkCE),
|
|
wantType: STNonStandard,
|
|
}, {
|
|
name: "almost v0 p2pk-schnorr-secp256k1 -- pubkey not pushed",
|
|
script: p("0x%s 2 CHECKSIGALT", pkCE),
|
|
wantType: STNonStandard,
|
|
}, {
|
|
name: "almost v0 p2pk-schnorr-secp256k1 -- malformed pubkey prefix",
|
|
script: p("DATA_33 0x08%s 2 CHECKSIGALT", pkCE[2:]),
|
|
wantType: STNonStandard,
|
|
}, {
|
|
// ---------------------------------------------------------------------
|
|
// Positive P2PK Schnorr secp256k1 tests.
|
|
// ---------------------------------------------------------------------
|
|
|
|
name: "v0 p2pk-schnorr-secp256k1 compressed even",
|
|
script: p("DATA_33 0x%s 2 CHECKSIGALT", pkCE),
|
|
wantType: STPubKeySchnorrSecp256k1,
|
|
wantData: hexToBytes(pkCE),
|
|
wantSigs: 1,
|
|
}, {
|
|
name: "v0 p2pk-schnorr-secp256k1 compressed odd",
|
|
script: p("DATA_33 0x%s 2 CHECKSIGALT", pkCO),
|
|
wantType: STPubKeySchnorrSecp256k1,
|
|
wantData: hexToBytes(pkCO),
|
|
wantSigs: 1,
|
|
}, {
|
|
// ---------------------------------------------------------------------
|
|
// Negative P2PKH ECDSA secp256k1 tests.
|
|
// ---------------------------------------------------------------------
|
|
|
|
name: "almost v0 p2pkh-ecdsa-secp256k1 -- wrong hash length",
|
|
script: p("DUP HASH160 DATA_21 0x00%s EQUALVERIFY CHECKSIG", h160CE),
|
|
wantType: STNonStandard,
|
|
}, {
|
|
// ---------------------------------------------------------------------
|
|
// Positive P2PKH ECDSA secp256k1 tests.
|
|
// ---------------------------------------------------------------------
|
|
|
|
name: "v0 p2pkh-ecdsa-secp256k1",
|
|
script: p("DUP HASH160 DATA_20 0x%s EQUALVERIFY CHECKSIG", h160CE),
|
|
wantType: STPubKeyHashEcdsaSecp256k1,
|
|
wantData: hexToBytes(h160CE),
|
|
wantSigs: 1,
|
|
}, {
|
|
// ---------------------------------------------------------------------
|
|
// Negative P2PKH Alt tests.
|
|
// ---------------------------------------------------------------------
|
|
|
|
name: "v0 p2pkh-alt unsupported signature type 0",
|
|
script: p("DUP HASH160 DATA_20 0x%s EQUALVERIFY 0 CHECKSIGALT",
|
|
h160CE),
|
|
wantType: STNonStandard,
|
|
}, {
|
|
name: "v0 p2pkh-alt unsupported signature type 3",
|
|
script: p("DUP HASH160 DATA_20 0x%s EQUALVERIFY 3 CHECKSIGALT",
|
|
h160CE),
|
|
wantType: STNonStandard,
|
|
}, {
|
|
name: "almost v0 p2pkh-alt -- signature type not a small int",
|
|
script: p("DUP HASH160 DATA_20 0x%s EQUALVERIFY DATA_1 2 CHECKSIGALT",
|
|
h160CE),
|
|
wantType: STNonStandard,
|
|
}, {
|
|
name: "almost v0 p2pkh-alt -- NOP for signature type",
|
|
script: p("DUP HASH160 DATA_20 0x%s EQUALVERIFY NOP CHECKSIGALT",
|
|
h160CE),
|
|
wantType: STNonStandard,
|
|
}, {
|
|
// ---------------------------------------------------------------------
|
|
// Negative P2PKH Ed25519 tests.
|
|
// ---------------------------------------------------------------------
|
|
|
|
name: "almost v0 p2pkh-ed25519 -- wrong hash length",
|
|
script: p("DUP HASH160 DATA_21 0x00%s EQUALVERIFY 1 CHECKSIGALT",
|
|
h160Ed),
|
|
wantType: STNonStandard,
|
|
}, {
|
|
// ---------------------------------------------------------------------
|
|
// Positive P2PKH Ed25519 tests.
|
|
// ---------------------------------------------------------------------
|
|
|
|
name: "v0 p2pkh-ed25519",
|
|
script: p("DUP HASH160 DATA_20 0x%s EQUALVERIFY 1 CHECKSIGALT",
|
|
h160Ed),
|
|
wantType: STPubKeyHashEd25519,
|
|
wantData: hexToBytes(h160Ed),
|
|
wantSigs: 1,
|
|
}, {
|
|
// ---------------------------------------------------------------------
|
|
// Negative P2PKH Schnorr secp256k1 tests.
|
|
// ---------------------------------------------------------------------
|
|
|
|
name: "almost v0 p2pkh-schnorr-secp256k1 -- wrong hash length",
|
|
script: p("DUP HASH160 DATA_21 0x00%s EQUALVERIFY 2 CHECKSIGALT",
|
|
h160CE),
|
|
wantType: STNonStandard,
|
|
}, {
|
|
// ---------------------------------------------------------------------
|
|
// Positive P2PKH Schnorr secp256k1 tests.
|
|
// ---------------------------------------------------------------------
|
|
|
|
name: "v0 p2pkh-schnorr-secp256k1",
|
|
script: p("DUP HASH160 DATA_20 0x%s EQUALVERIFY 2 CHECKSIGALT",
|
|
h160CE),
|
|
wantType: STPubKeyHashSchnorrSecp256k1,
|
|
wantData: hexToBytes(h160CE),
|
|
wantSigs: 1,
|
|
}, {
|
|
name: "v0 p2pkh-schnorr-secp256k1 2",
|
|
script: p("DUP HASH160 DATA_20 0x%s EQUALVERIFY 2 CHECKSIGALT",
|
|
h160CE2),
|
|
wantType: STPubKeyHashSchnorrSecp256k1,
|
|
wantData: hexToBytes(h160CE2),
|
|
wantSigs: 1,
|
|
}, {
|
|
// ---------------------------------------------------------------------
|
|
// Negative P2SH tests.
|
|
// ---------------------------------------------------------------------
|
|
|
|
name: "almost v0 p2sh -- wrong hash length",
|
|
script: p("HASH160 DATA_21 0x00%s EQUAL", p2sh),
|
|
wantType: STNonStandard,
|
|
}, {
|
|
name: "almost v0 p2sh -- trailing opcode",
|
|
script: p("HASH160 DATA_20 0x%s EQUAL TRUE", p2sh),
|
|
wantType: STNonStandard,
|
|
}, {
|
|
// ---------------------------------------------------------------------
|
|
// Positive P2SH tests.
|
|
// ---------------------------------------------------------------------
|
|
|
|
name: "v0 p2sh",
|
|
script: p("HASH160 DATA_20 0x%s EQUAL", p2sh),
|
|
wantType: STScriptHash,
|
|
wantData: hexToBytes(p2sh),
|
|
wantSigs: 1,
|
|
}, {
|
|
// ---------------------------------------------------------------------
|
|
// Negative ECDSA multisig secp256k1 tests.
|
|
// ---------------------------------------------------------------------
|
|
|
|
name: "almost v0 multisig 1-of-2 -- mixed (un)compressed pubkeys",
|
|
script: p("1 DATA_65 0x%s DATA_33 0x%s 2 CHECKMULTISIG", pkUE, pkCO),
|
|
wantType: STNonStandard,
|
|
}, {
|
|
name: "almost v0 multisig -- no req sigs",
|
|
script: p("0 0 CHECKMULTISIG"),
|
|
wantType: STNonStandard,
|
|
}, {
|
|
name: "almost v0 multisig -- invalid pubkey",
|
|
script: p("1 DATA_32 0x%s 1 CHECKMULTISIG", pkCE[2:]),
|
|
wantType: STNonStandard,
|
|
}, {
|
|
name: "almost v0 multisig -- hybrid pubkey",
|
|
script: p("1 DATA_65 0x%s 1 CHECKMULTISIG", pkHO),
|
|
wantType: STNonStandard,
|
|
}, {
|
|
name: "almost v0 multisig -- invalid number of signatures",
|
|
script: p("DUP DATA_33 0x%s 1 CHECKMULTISIG", pkCE),
|
|
wantType: STNonStandard,
|
|
}, {
|
|
name: "almost v0 multisig -- ends with CHECKSIG instead",
|
|
script: p("1 DATA_33 0x%s 1 CHECKSIG", pkCE),
|
|
wantType: STNonStandard,
|
|
}, {
|
|
name: "almost v0 multisig -- num required sigs not small int",
|
|
script: p("DATA_1 1 DATA_33 0x%s 1 CHECKMULTISIG", pkCE),
|
|
wantType: STNonStandard,
|
|
}, {
|
|
name: "almost v0 multisig -- num public keys not small int",
|
|
script: p("1 DATA_33 0x%s DATA_1 1 CHECKMULTISIG", pkCE),
|
|
wantType: STNonStandard,
|
|
}, {
|
|
name: "almost v0 multisig -- missing num public keys",
|
|
script: p("1 DATA_33 0x%s CHECKMULTISIG", pkCE),
|
|
wantType: STNonStandard,
|
|
}, {
|
|
name: "almost v0 multisig -- num pubkeys does not match given keys",
|
|
script: p("2 DATA_33 0x%s DATA_33 0x%s 3 CHECKMULTISIG", pkCE, pkCO),
|
|
wantType: STNonStandard,
|
|
}, {
|
|
name: "almost v0 multisig -- fewer pubkeys than num required sigs",
|
|
script: p("1 0 CHECKMULTISIG"),
|
|
wantType: STNonStandard,
|
|
}, {
|
|
name: "almost v0 multisig -- CHECKMULTISIGVERIFY",
|
|
script: p("1 DATA_33 0x%s 1 CHECKMULTISIGVERIFY", pkCE),
|
|
wantType: STNonStandard,
|
|
}, {
|
|
name: "almost v0 multisig -- extra NOP prior to final opcode",
|
|
script: p("1 DATA_33 0x%s 1 NOP CHECKMULTISIG", pkCE),
|
|
wantType: STNonStandard,
|
|
}, {
|
|
name: "almost v0 multisig -- trailing opcode",
|
|
script: p("1 DATA_33 0x%s 1 CHECKMULTISIG TRUE", pkCE),
|
|
wantType: STNonStandard,
|
|
}, {
|
|
name: "almost v0 multisig -- no pubkeys specified",
|
|
script: p("1 CHECKMULTISIG"),
|
|
wantType: STNonStandard,
|
|
}, {
|
|
// ---------------------------------------------------------------------
|
|
// Positive ECDSA multisig secp256k1 tests.
|
|
// ---------------------------------------------------------------------
|
|
|
|
name: "v0 multisig 1-of-1 compressed pubkey",
|
|
script: p("1 DATA_33 0x%s 1 CHECKMULTISIG", pkCE),
|
|
wantType: STMultiSig,
|
|
wantData: MultiSigDetailsV0{
|
|
RequiredSigs: 1,
|
|
NumPubKeys: 1,
|
|
PubKeys: [][]byte{hexToBytes(pkCE)},
|
|
Valid: true,
|
|
},
|
|
wantSigs: 1,
|
|
}, {
|
|
name: "v0 multisig 1-of-2 compressed pubkeys",
|
|
script: p("1 DATA_33 0x%s DATA_33 0x%s 2 CHECKMULTISIG", pkCE, pkCE2),
|
|
wantType: STMultiSig,
|
|
wantData: MultiSigDetailsV0{
|
|
RequiredSigs: 1,
|
|
NumPubKeys: 2,
|
|
PubKeys: [][]byte{hexToBytes(pkCE), hexToBytes(pkCE2)},
|
|
Valid: true,
|
|
},
|
|
wantSigs: 1,
|
|
}, {
|
|
name: "v0 multisig 2-of-3 compressed pubkeys",
|
|
script: p("2 DATA_33 0x%s DATA_33 0x%s DATA_33 0x%s 3 CHECKMULTISIG",
|
|
pkCE, pkCE2, pkCO),
|
|
wantType: STMultiSig,
|
|
wantData: MultiSigDetailsV0{
|
|
RequiredSigs: 2,
|
|
NumPubKeys: 3,
|
|
PubKeys: [][]byte{
|
|
hexToBytes(pkCE), hexToBytes(pkCE2), hexToBytes(pkCO),
|
|
},
|
|
Valid: true,
|
|
},
|
|
wantSigs: 2,
|
|
}, {
|
|
// ---------------------------------------------------------------------
|
|
// Negative ECDSA multisig secp256k1 redeem script tests.
|
|
// ---------------------------------------------------------------------
|
|
|
|
name: "almost v0 multisig redeem script -- no req sigs",
|
|
script: p("DATA_3 0 0 CHECKMULTISIG"),
|
|
isSig: true,
|
|
wantType: STNonStandard,
|
|
}, {
|
|
name: "almost v0 multisig 1-of-1 redeem script -- trailing opcode",
|
|
script: p("DATA_38 1 DATA_33 0x%s 1 CHECKMULTISIG TRUE", pkCE),
|
|
isSig: true,
|
|
wantType: STNonStandard,
|
|
}, {
|
|
name: "almost v0 multisig 1-of-1 redeem script -- parse error",
|
|
script: p("DATA_38 1 DATA_33 0x%s 1 CHECKMULTISIG", pkCE),
|
|
isSig: true,
|
|
wantType: STNonStandard,
|
|
}, {
|
|
// ---------------------------------------------------------------------
|
|
// Positive ECDSA multisig secp256k1 redeem script tests.
|
|
// ---------------------------------------------------------------------
|
|
|
|
name: "v0 multisig 1-of-1 compressed pubkey redeem script",
|
|
script: p("DATA_37 1 DATA_33 0x%s 1 CHECKMULTISIG", pkCE),
|
|
isSig: true,
|
|
wantType: STMultiSig,
|
|
wantData: p("1 DATA_33 0x%s 1 CHECKMULTISIG", pkCE),
|
|
}, {
|
|
name: "v0 multisig 1-of-2 compressed pubkeys redeem script",
|
|
script: p("DATA_71 1 DATA_33 0x%s DATA_33 0x%s 2 CHECKMULTISIG", pkCE,
|
|
pkCE2),
|
|
isSig: true,
|
|
wantType: STMultiSig,
|
|
wantData: p("1 DATA_33 0x%s DATA_33 0x%s 2 CHECKMULTISIG", pkCE, pkCE2),
|
|
}, {
|
|
// ---------------------------------------------------------------------
|
|
// Negative nulldata tests.
|
|
// ---------------------------------------------------------------------
|
|
|
|
name: "almost v0 nulldata -- NOP instead of data push",
|
|
script: p("RETURN NOP"),
|
|
wantType: STNonStandard,
|
|
}, {
|
|
name: "almost v0 nulldata -- non-canonical small int push (DATA_1 vs 12)",
|
|
script: p("RETURN DATA_1 0x0c"),
|
|
wantType: STNonStandard,
|
|
}, {
|
|
name: "almost v0 nulldata -- non-canonical small int push (PUSHDATA1 vs 12)",
|
|
script: p("RETURN PUSHDATA1 0x01 0x0c"),
|
|
wantType: STNonStandard,
|
|
}, {
|
|
name: "almost v0 nulldata -- non-canonical 60-byte push (PUSHDATA1 vs DATA_60)",
|
|
script: p("RETURN PUSHDATA1 0x3c 0x046708afdb0fe5548271967f1a67130b7105" +
|
|
"cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3046708afdb0fe5548271" +
|
|
"967f1a67130b7105cd6a"),
|
|
wantType: STNonStandard,
|
|
}, {
|
|
name: "almost v0 nulldata -- non-canonical 12-byte push (PUSHDATA2)",
|
|
script: p("RETURN PUSHDATA2 0x0c00 0x046708afdb0fe5548271967f"),
|
|
wantType: STNonStandard,
|
|
}, {
|
|
name: "almost v0 nulldata -- non-canonical 12-byte push (PUSHDATA4)",
|
|
script: p("RETURN PUSHDATA4 0x0c000000 0x046708afdb0fe5548271967f"),
|
|
wantType: STNonStandard,
|
|
}, {
|
|
name: "almost v0 nulldata -- exceeds max standard push",
|
|
script: p("RETURN PUSHDATA2 0x0101 0x01{257}"),
|
|
wantType: STNonStandard,
|
|
}, {
|
|
name: "almost v0 nulldata -- trailing opcode",
|
|
script: p("RETURN 4 TRUE"),
|
|
wantType: STNonStandard,
|
|
}, {
|
|
// ---------------------------------------------------------------------
|
|
// Positive nulldata tests.
|
|
// ---------------------------------------------------------------------
|
|
|
|
name: "v0 nulldata no data push",
|
|
script: p("RETURN"),
|
|
wantType: STNullData,
|
|
}, {
|
|
name: "v0 nulldata single zero push",
|
|
script: p("RETURN 0"),
|
|
wantType: STNullData,
|
|
}, {
|
|
name: "v0 nulldata small int push",
|
|
script: p("RETURN 1"),
|
|
wantType: STNullData,
|
|
}, {
|
|
name: "v0 nulldata max small int push",
|
|
script: p("RETURN 16"),
|
|
wantType: STNullData,
|
|
}, {
|
|
name: "v0 nulldata small data push",
|
|
script: p("RETURN DATA_8 0x046708afdb0fe554"),
|
|
wantType: STNullData,
|
|
}, {
|
|
name: "v0 nulldata 60-byte push",
|
|
script: p("RETURN 0x3c 0x046708afdb0fe5548271967f1a67130b7105cd6a828e03" +
|
|
"909a67962e0ea1f61deb649f6bc3f4cef3046708afdb0fe5548271967f1a6713" +
|
|
"0b7105cd6a"),
|
|
wantType: STNullData,
|
|
}, {
|
|
name: "v0 nulldata max standard push",
|
|
script: p("RETURN PUSHDATA2 0x0001 0x01{256}"),
|
|
wantType: STNullData,
|
|
}, {
|
|
// ---------------------------------------------------------------------
|
|
// Negative stake submission P2PKH tests.
|
|
// ---------------------------------------------------------------------
|
|
|
|
name: "almost v0 stake sub p2pkh-ecdsa-secp256k1 -- wrong hash length",
|
|
script: p("SSTX DUP HASH160 DATA_21 0x00%s EQUALVERIFY CHECKSIG",
|
|
h160CE),
|
|
wantType: STNonStandard,
|
|
}, {
|
|
// ---------------------------------------------------------------------
|
|
// Positive stake submission P2PKH tests.
|
|
// ---------------------------------------------------------------------
|
|
|
|
name: "v0 stake submission p2pkh-ecdsa-secp256k1",
|
|
script: p("SSTX DUP HASH160 DATA_20 0x%s EQUALVERIFY CHECKSIG", h160CE),
|
|
wantType: STStakeSubmissionPubKeyHash,
|
|
wantData: hexToBytes(h160CE),
|
|
wantSigs: 1,
|
|
}, {
|
|
// ---------------------------------------------------------------------
|
|
// Negative stake submission P2SH tests.
|
|
// ---------------------------------------------------------------------
|
|
|
|
name: "almost v0 stake submission p2sh -- wrong hash length",
|
|
script: p("SSTX HASH160 DATA_21 0x00%s EQUAL", p2sh),
|
|
wantType: STNonStandard,
|
|
}, {
|
|
// ---------------------------------------------------------------------
|
|
// Positive stake submission P2SH tests.
|
|
// ---------------------------------------------------------------------
|
|
|
|
name: "v0 stake submission p2sh",
|
|
script: p("SSTX HASH160 DATA_20 0x%s EQUAL", p2sh),
|
|
wantType: STStakeSubmissionScriptHash,
|
|
wantData: hexToBytes(p2sh),
|
|
wantSigs: 1,
|
|
}, {
|
|
// ---------------------------------------------------------------------
|
|
// Negative stake submission generation P2PKH tests.
|
|
// ---------------------------------------------------------------------
|
|
|
|
name: "almost v0 stake gen p2pkh-ecdsa-secp256k1 -- wrong hash length",
|
|
script: p("SSGEN DUP HASH160 DATA_21 0x00%s EQUALVERIFY CHECKSIG",
|
|
h160CE),
|
|
wantType: STNonStandard,
|
|
}, {
|
|
// ---------------------------------------------------------------------
|
|
// Positive stake submission generation P2PKH tests.
|
|
// ---------------------------------------------------------------------
|
|
|
|
name: "v0 stake gen p2pkh-ecdsa-secp256k1",
|
|
script: p("SSGEN DUP HASH160 DATA_20 0x%s EQUALVERIFY CHECKSIG",
|
|
h160CE),
|
|
wantType: STStakeGenPubKeyHash,
|
|
wantData: hexToBytes(h160CE),
|
|
wantSigs: 1,
|
|
}, {
|
|
// ---------------------------------------------------------------------
|
|
// Negative stake submission generation P2SH tests.
|
|
// ---------------------------------------------------------------------
|
|
|
|
name: "almost v0 stake gen p2sh -- wrong hash length",
|
|
script: p("SSGEN HASH160 DATA_21 0x00%s EQUAL", p2sh),
|
|
wantType: STNonStandard,
|
|
}, {
|
|
// ---------------------------------------------------------------------
|
|
// Positive stake submission generation P2SH tests.
|
|
// ---------------------------------------------------------------------
|
|
|
|
name: "v0 stake gen p2sh",
|
|
script: p("SSGEN HASH160 DATA_20 0x%s EQUAL", p2sh),
|
|
wantType: STStakeGenScriptHash,
|
|
wantData: hexToBytes(p2sh),
|
|
wantSigs: 1,
|
|
}, {
|
|
// ---------------------------------------------------------------------
|
|
// Negative stake submission revocation P2PKH tests.
|
|
// ---------------------------------------------------------------------
|
|
|
|
name: "almost v0 stake revoke p2pkh-ecdsa-secp256k1 -- wrong hash length",
|
|
script: p("SSRTX DUP HASH160 DATA_21 0x00%s EQUALVERIFY CHECKSIG",
|
|
h160CE),
|
|
wantType: STNonStandard,
|
|
}, {
|
|
// ---------------------------------------------------------------------
|
|
// Positive stake submission revocation P2PKH tests.
|
|
// ---------------------------------------------------------------------
|
|
|
|
name: "v0 stake revoke p2pkh-ecdsa-secp256k1",
|
|
script: p("SSRTX DUP HASH160 DATA_20 0x%s EQUALVERIFY CHECKSIG",
|
|
h160CE),
|
|
wantType: STStakeRevocationPubKeyHash,
|
|
wantData: hexToBytes(h160CE),
|
|
wantSigs: 1,
|
|
}, {
|
|
// ---------------------------------------------------------------------
|
|
// Negative stake submission revocation P2SH tests.
|
|
// ---------------------------------------------------------------------
|
|
|
|
name: "almost v0 stake revoke p2sh -- wrong hash length",
|
|
script: p("SSRTX HASH160 DATA_21 0x00%s EQUAL", p2sh),
|
|
wantType: STNonStandard,
|
|
}, {
|
|
// ---------------------------------------------------------------------
|
|
// Positive stake submission revocation P2SH tests.
|
|
// ---------------------------------------------------------------------
|
|
|
|
name: "v0 stake revoke p2sh",
|
|
script: p("SSRTX HASH160 DATA_20 0x%s EQUAL", p2sh),
|
|
wantType: STStakeRevocationScriptHash,
|
|
wantData: hexToBytes(p2sh),
|
|
wantSigs: 1,
|
|
}, {
|
|
// ---------------------------------------------------------------------
|
|
// Negative stake submission change P2PKH tests.
|
|
// ---------------------------------------------------------------------
|
|
|
|
name: "almost v0 stake change p2pkh-ecdsa-secp256k1 -- wrong hash length",
|
|
script: p("SSTXCHANGE DUP HASH160 DATA_21 0x00%s EQUALVERIFY CHECKSIG",
|
|
h160CE),
|
|
wantType: STNonStandard,
|
|
}, {
|
|
// ---------------------------------------------------------------------
|
|
// Positive stake submission change P2PKH tests.
|
|
// ---------------------------------------------------------------------
|
|
|
|
name: "v0 stake change p2pkh-ecdsa-secp256k1",
|
|
script: p("SSTXCHANGE DUP HASH160 DATA_20 0x%s EQUALVERIFY CHECKSIG",
|
|
h160CE),
|
|
wantType: STStakeChangePubKeyHash,
|
|
wantData: hexToBytes(h160CE),
|
|
wantSigs: 1,
|
|
}, {
|
|
// ---------------------------------------------------------------------
|
|
// Negative stake submission change P2SH tests.
|
|
// ---------------------------------------------------------------------
|
|
|
|
name: "almost v0 stake change p2sh -- wrong hash length",
|
|
script: p("SSTXCHANGE HASH160 DATA_21 0x00%s EQUAL", p2sh),
|
|
wantType: STNonStandard,
|
|
}, {
|
|
// ---------------------------------------------------------------------
|
|
// Positive stake submission change P2SH tests.
|
|
// ---------------------------------------------------------------------
|
|
|
|
name: "v0 stake change p2sh",
|
|
script: p("SSTXCHANGE HASH160 DATA_20 0x%s EQUAL", p2sh),
|
|
wantType: STStakeChangeScriptHash,
|
|
wantData: hexToBytes(p2sh),
|
|
wantSigs: 1,
|
|
}, {
|
|
// ---------------------------------------------------------------------
|
|
// Negative treasury add tests.
|
|
// ---------------------------------------------------------------------
|
|
|
|
name: "almost v0 treasury add -- trailing opcode",
|
|
script: p("TADD TRUE"),
|
|
wantType: STNonStandard,
|
|
}, {
|
|
name: "almost v0 treasury add -- two TADD",
|
|
script: p("TADD TADD"),
|
|
wantType: STNonStandard,
|
|
}, {
|
|
// ---------------------------------------------------------------------
|
|
// Positive treasury add tests.
|
|
// ---------------------------------------------------------------------
|
|
|
|
name: "v0 treasury add",
|
|
script: p("TADD"),
|
|
wantType: STTreasuryAdd,
|
|
}, {
|
|
// ---------------------------------------------------------------------
|
|
// Negative treasury generation P2PKH tests.
|
|
// ---------------------------------------------------------------------
|
|
|
|
name: "almost v0 trsy gen p2pkh-ecdsa-secp256k1 -- wrong hash length",
|
|
script: p("TGEN DUP HASH160 DATA_21 0x00%s EQUALVERIFY CHECKSIG",
|
|
h160CE),
|
|
wantType: STNonStandard,
|
|
}, {
|
|
// ---------------------------------------------------------------------
|
|
// Positive treasury generation P2PKH tests.
|
|
// ---------------------------------------------------------------------
|
|
|
|
name: "v0 treasury generation p2pkh-ecdsa-secp256k1",
|
|
script: p("TGEN DUP HASH160 DATA_20 0x%s EQUALVERIFY CHECKSIG",
|
|
h160CE),
|
|
wantType: STTreasuryGenPubKeyHash,
|
|
wantData: hexToBytes(h160CE),
|
|
wantSigs: 1,
|
|
}, {
|
|
// ---------------------------------------------------------------------
|
|
// Negative treasury generation P2SH tests.
|
|
// ---------------------------------------------------------------------
|
|
|
|
name: "almost v0 treasury generation p2sh -- wrong hash length",
|
|
script: p("TGEN HASH160 DATA_21 0x00%s EQUAL", p2sh),
|
|
wantType: STNonStandard,
|
|
}, {
|
|
// ---------------------------------------------------------------------
|
|
// Positive treasury generation P2SH tests.
|
|
// ---------------------------------------------------------------------
|
|
|
|
name: "v0 treasury generation p2sh",
|
|
script: p("TGEN HASH160 DATA_20 0x%s EQUAL", p2sh),
|
|
wantType: STTreasuryGenScriptHash,
|
|
wantData: hexToBytes(p2sh),
|
|
wantSigs: 1,
|
|
}}
|
|
}()
|
|
|
|
// asByteSlice attempts to convert the data associated with the passed script
|
|
// test to a byte slice or causes a fatal test error.
|
|
func asByteSlice(t *testing.T, test scriptTest) []byte {
|
|
t.Helper()
|
|
|
|
want, ok := test.wantData.([]byte)
|
|
if !ok {
|
|
t.Fatalf("%q: unexpected want data type -- got %T", test.name,
|
|
test.wantData)
|
|
}
|
|
return want
|
|
}
|
|
|
|
// TestExtractPubKeysV0 ensures that extracting a public key from the various
|
|
// version 0 pay-to-pubkey-ecdsa-secp256k1 style scripts works as intended
|
|
// for all of the version 0 test scripts.
|
|
func TestExtractPubKeysV0(t *testing.T) {
|
|
for _, test := range scriptV0Tests {
|
|
// Determine the expected data based on the expected script type and
|
|
// data specified in the test.
|
|
var want, wantCompressed, wantUncompressed []byte
|
|
if test.wantType == STPubKeyEcdsaSecp256k1 {
|
|
want = asByteSlice(t, test)
|
|
if len(want) == 33 {
|
|
wantCompressed = want
|
|
} else if len(want) == 65 {
|
|
wantUncompressed = want
|
|
}
|
|
}
|
|
|
|
testExtract := func(fn func(script []byte) []byte, want []byte) {
|
|
t.Helper()
|
|
|
|
got := fn(test.script)
|
|
if !bytes.Equal(got, want) {
|
|
t.Errorf("%q: unexpected pubkey -- got %x, want %x (script %x)",
|
|
test.name, got, want, test.script)
|
|
}
|
|
}
|
|
testExtract(ExtractPubKeyV0, want)
|
|
testExtract(ExtractCompressedPubKeyV0, wantCompressed)
|
|
testExtract(ExtractUncompressedPubKeyV0, wantUncompressed)
|
|
}
|
|
}
|
|
|
|
// TestExtractPubKeyAltDetailsV0 ensures that extracting a public key and
|
|
// signature type from the various version 0 pay-to-alt-pubkey style scripts
|
|
// works as intended for all of the version 0 test scripts.
|
|
func TestExtractPubKeyAltDetailsV0(t *testing.T) {
|
|
for _, test := range scriptV0Tests {
|
|
// Determine the expected data based on the expected script type and
|
|
// data specified in the test.
|
|
var wantBytes []byte
|
|
var wantSigType dcrec.SignatureType
|
|
switch test.wantType {
|
|
case STPubKeyEd25519:
|
|
wantBytes = asByteSlice(t, test)
|
|
wantSigType = dcrec.STEd25519
|
|
|
|
case STPubKeySchnorrSecp256k1:
|
|
wantBytes = asByteSlice(t, test)
|
|
wantSigType = dcrec.STSchnorrSecp256k1
|
|
}
|
|
|
|
gotBytes, gotSigType := ExtractPubKeyAltDetailsV0(test.script)
|
|
if !bytes.Equal(gotBytes, wantBytes) {
|
|
t.Errorf("%q: unexpected pubkey -- got %x, want %x", test.name,
|
|
gotBytes, wantBytes)
|
|
continue
|
|
}
|
|
if gotBytes != nil && gotSigType != wantSigType {
|
|
t.Errorf("%q: unexpected sig type -- got %d, want %d", test.name,
|
|
gotSigType, wantSigType)
|
|
continue
|
|
}
|
|
}
|
|
}
|
|
|
|
// TestExtractPubKeyEd25519V0 ensures that extracting a public key from the
|
|
// various version 0 pay-to-pubkey-ed25519 scripts works as intended for all of
|
|
// the version 0 test scripts.
|
|
func TestExtractPubKeyEd25519V0(t *testing.T) {
|
|
for _, test := range scriptV0Tests {
|
|
// Determine the expected data based on the expected script type and
|
|
// data specified in the test.
|
|
var want []byte
|
|
if test.wantType == STPubKeyEd25519 {
|
|
want = asByteSlice(t, test)
|
|
}
|
|
|
|
got := ExtractPubKeyEd25519V0(test.script)
|
|
if !bytes.Equal(got, want) {
|
|
t.Errorf("%q: unexpected pubkey -- got %x, want %x", test.name,
|
|
got, want)
|
|
continue
|
|
}
|
|
}
|
|
}
|
|
|
|
// TestExtractPubKeySchnorrSecp256k1V0 ensures that extracting a public key from
|
|
// the various version 0 pay-to-pubkey-schnorr-secp256k1 scripts works as
|
|
// intended for all of the version 0 test scripts.
|
|
func TestExtractPubKeySchnorrSecp256k1V0(t *testing.T) {
|
|
for _, test := range scriptV0Tests {
|
|
// Determine the expected data based on the expected script type and
|
|
// data specified in the test.
|
|
var want []byte
|
|
if test.wantType == STPubKeySchnorrSecp256k1 {
|
|
want = asByteSlice(t, test)
|
|
}
|
|
|
|
got := ExtractPubKeySchnorrSecp256k1V0(test.script)
|
|
if !bytes.Equal(got, want) {
|
|
t.Errorf("%q: unexpected pubkey -- got %x, want %x", test.name,
|
|
got, want)
|
|
continue
|
|
}
|
|
}
|
|
}
|
|
|
|
// TestExtractPubKeyHashV0 ensures that extracting a public key hash from the
|
|
// various version 0 pay-to-pubkey-hash-ecdsa-secp256k1 scripts works as
|
|
// intended for all of the version 0 test scripts.
|
|
func TestExtractPubKeyHashV0(t *testing.T) {
|
|
for _, test := range scriptV0Tests {
|
|
// Determine the expected data based on the expected script type and
|
|
// data specified in the test.
|
|
var want []byte
|
|
if test.wantType == STPubKeyHashEcdsaSecp256k1 {
|
|
want = asByteSlice(t, test)
|
|
}
|
|
|
|
got := ExtractPubKeyHashV0(test.script)
|
|
if !bytes.Equal(got, want) {
|
|
t.Errorf("%q: unexpected pubkey hash -- got %x, want %x", test.name,
|
|
got, want)
|
|
continue
|
|
}
|
|
}
|
|
}
|
|
|
|
// TestExtractPubKeyHashAltDetailsV0 ensures that extracting a public key hash
|
|
// and signature type from the version 0 pay-to-alt-pubkey-hash style scripts
|
|
// works as intended for all of the version 0 test scripts.
|
|
func TestExtractPubKeyHashAltDetailsV0(t *testing.T) {
|
|
for _, test := range scriptV0Tests {
|
|
// Determine the expected data based on the expected script type and
|
|
// data specified in the test.
|
|
var wantBytes []byte
|
|
var wantSigType dcrec.SignatureType
|
|
switch test.wantType {
|
|
case STPubKeyHashEd25519:
|
|
wantBytes = asByteSlice(t, test)
|
|
wantSigType = dcrec.STEd25519
|
|
|
|
case STPubKeyHashSchnorrSecp256k1:
|
|
wantBytes = asByteSlice(t, test)
|
|
wantSigType = dcrec.STSchnorrSecp256k1
|
|
}
|
|
|
|
gotBytes, gotSigType := ExtractPubKeyHashAltDetailsV0(test.script)
|
|
if !bytes.Equal(gotBytes, wantBytes) {
|
|
t.Errorf("%q: unexpected pubkey hash -- got %x, want %x", test.name,
|
|
gotBytes, wantBytes)
|
|
continue
|
|
}
|
|
if gotBytes != nil && gotSigType != wantSigType {
|
|
t.Errorf("%q: unexpected sig type -- got %d, want %d", test.name,
|
|
gotSigType, wantSigType)
|
|
continue
|
|
}
|
|
}
|
|
}
|
|
|
|
// TestExtractPubKeyHashEd25519V0 ensures that extracting a public key hash from
|
|
// version 0 pay-to-pubkey-hash-ed25519 scripts works as intended for all of the
|
|
// version 0 test scripts.
|
|
func TestExtractPubKeyHashEd25519V0(t *testing.T) {
|
|
for _, test := range scriptV0Tests {
|
|
// Determine the expected data based on the expected script type and
|
|
// data specified in the test.
|
|
var want []byte
|
|
if test.wantType == STPubKeyHashEd25519 {
|
|
want = asByteSlice(t, test)
|
|
}
|
|
|
|
got := ExtractPubKeyHashEd25519V0(test.script)
|
|
if !bytes.Equal(got, want) {
|
|
t.Errorf("%q: unexpected pubkey hash -- got %x, want %x", test.name,
|
|
got, want)
|
|
continue
|
|
}
|
|
}
|
|
}
|
|
|
|
// TestExtractPubKeyHashSchnorrSecp256k1V0 ensures that extracting a public key
|
|
// hash from version 0 pay-to-pubkey-hash-schnor-secp256k1 scripts works as
|
|
// intended for all of the version 0 test scripts.
|
|
func TestExtractPubKeyHashSchnorrSecp256k1V0(t *testing.T) {
|
|
for _, test := range scriptV0Tests {
|
|
// Determine the expected data based on the expected script type and
|
|
// data specified in the test.
|
|
var want []byte
|
|
if test.wantType == STPubKeyHashSchnorrSecp256k1 {
|
|
want = asByteSlice(t, test)
|
|
}
|
|
|
|
got := ExtractPubKeyHashSchnorrSecp256k1V0(test.script)
|
|
if !bytes.Equal(got, want) {
|
|
t.Errorf("%q: unexpected pubkey hash -- got %x, want %x", test.name,
|
|
got, want)
|
|
continue
|
|
}
|
|
}
|
|
}
|
|
|
|
// TestExtractScriptHashV0 ensures that extracting a script hash from the
|
|
// various version 0 pay-to-script-hash scripts works as intended for all of the
|
|
// version 0 test scripts.
|
|
func TestExtractScriptHashV0(t *testing.T) {
|
|
for _, test := range scriptV0Tests {
|
|
// Determine the expected data based on the expected script type and
|
|
// data specified in the test.
|
|
var want []byte
|
|
if test.wantType == STScriptHash {
|
|
want = asByteSlice(t, test)
|
|
}
|
|
|
|
got := ExtractScriptHashV0(test.script)
|
|
if !bytes.Equal(got, want) {
|
|
t.Errorf("%q: unexpected script hash -- got %x, want %x", test.name,
|
|
got, want)
|
|
continue
|
|
}
|
|
}
|
|
}
|
|
|
|
// TestExtractMultiSigScriptDetailsV0 ensures that extracting details about a
|
|
// version 0 ECDSA multisignature script works as intended for all of the
|
|
// version 0 test scripts.
|
|
func TestExtractMultiSigScriptDetailsV0(t *testing.T) {
|
|
for _, test := range scriptV0Tests {
|
|
// Determine the expected data based on the expected script type and
|
|
// data specified in the test.
|
|
var want MultiSigDetailsV0
|
|
if test.wantType == STMultiSig && !test.isSig {
|
|
var ok bool
|
|
want, ok = test.wantData.(MultiSigDetailsV0)
|
|
if !ok {
|
|
t.Fatalf("%q: unexpected want data type -- got %T", test.name,
|
|
test.wantData)
|
|
}
|
|
}
|
|
|
|
// Attempt to extract the multisig data from the script and ensure
|
|
// the individual fields of the extracted data is accurate.
|
|
got := ExtractMultiSigScriptDetailsV0(test.script, true)
|
|
if got.Valid != want.Valid {
|
|
t.Errorf("%q: unexpected validity -- got %v, want %v", test.name,
|
|
got.Valid, want.Valid)
|
|
continue
|
|
}
|
|
if got.RequiredSigs != want.RequiredSigs {
|
|
t.Errorf("%q: unexpected required sigs -- got %d, want %d",
|
|
test.name, got.RequiredSigs, want.RequiredSigs)
|
|
continue
|
|
}
|
|
if got.NumPubKeys != want.NumPubKeys {
|
|
t.Errorf("%q: unexpected num public keys -- got %d, want %d",
|
|
test.name, got.NumPubKeys, want.NumPubKeys)
|
|
continue
|
|
}
|
|
if !reflect.DeepEqual(got.PubKeys, want.PubKeys) {
|
|
t.Errorf("%q: unexpected extracted pubkeys -- got %x, want %x",
|
|
test.name, got.PubKeys, want.PubKeys)
|
|
continue
|
|
}
|
|
}
|
|
}
|
|
|
|
// TestMultiSigRedeemScriptFromScriptSigV0 ensures extracting a version 0 ECDSA
|
|
// multisignature redeem script returns the expected scripts for the version 0
|
|
// test scripts that are actually multisignature redeem scripts.
|
|
func TestMultiSigRedeemScriptFromScriptSigV0(t *testing.T) {
|
|
// Add an additional test to ensure empty redeem scripts are handled
|
|
// correctly.
|
|
tests := []scriptTest{{
|
|
name: "v0 empty script",
|
|
script: nil,
|
|
isSig: true,
|
|
wantData: []byte(nil),
|
|
}}
|
|
for _, test := range scriptV0Tests {
|
|
// Per the documentation, unlike most of the extraction funcs, the
|
|
// multisig redeem script extraction function is only valid for scripts
|
|
// that have already been determined to be of the correct form.
|
|
if test.wantType != STMultiSig || !test.isSig {
|
|
continue
|
|
}
|
|
|
|
tests = append(tests, test)
|
|
}
|
|
|
|
for _, test := range tests {
|
|
want := asByteSlice(t, test)
|
|
got := MultiSigRedeemScriptFromScriptSigV0(test.script)
|
|
if !bytes.Equal(got, want) {
|
|
t.Errorf("%q: unexpected redeem script -- got %x, want %x",
|
|
test.name, got, want)
|
|
continue
|
|
}
|
|
}
|
|
}
|
|
|
|
// TestMultiSigScriptV0 ensures the version 0 ECDSA multisignature script
|
|
// creation function returns the expected scripts and errors.
|
|
func TestMultiSigScriptV0(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
// mainnet p2pk 13CG6SJ3yHUXo4Cr2RY4THLLJrNFuG3gUg
|
|
p2pkCompressedMain := hexToBytes("02192d74d0cb94344c9569c2e77901573d8d790" +
|
|
"3c3ebec3a957724895dca52c6b4")
|
|
p2pkCompressed2Main := hexToBytes("03b0bd634234abbb1ba1e986e884185c61cf43" +
|
|
"e001f9137f23c2c409273eb16e65")
|
|
p2pkUncompressedMain := hexToBytes("0411db93e1dcdb8a016b49840f8c53bc1eb68" +
|
|
"a382e97b1482ecad7b148a6909a5cb2e0eaddfb84ccf9744464f82e160bfa9b8b64f" +
|
|
"9d4c03f999b8643f656b412a3")
|
|
|
|
tests := []struct {
|
|
name string
|
|
threshold int
|
|
pubKeys [][]byte
|
|
expected string
|
|
err error
|
|
}{{
|
|
name: "normal 1-of-2",
|
|
threshold: 1,
|
|
pubKeys: [][]byte{p2pkCompressedMain, p2pkCompressed2Main},
|
|
expected: fmt.Sprintf("1 DATA_%d 0x%x DATA_%d 0x%x 2 CHECKMULTISIG",
|
|
len(p2pkCompressedMain), p2pkCompressedMain,
|
|
len(p2pkCompressed2Main), p2pkCompressed2Main),
|
|
}, {
|
|
name: "normal 2-of-2",
|
|
threshold: 2,
|
|
pubKeys: [][]byte{p2pkCompressedMain, p2pkCompressed2Main},
|
|
expected: fmt.Sprintf("2 DATA_%d 0x%x DATA_%d 0x%x 2 CHECKMULTISIG",
|
|
len(p2pkCompressedMain), p2pkCompressedMain,
|
|
len(p2pkCompressed2Main), p2pkCompressed2Main),
|
|
}, {
|
|
name: "threshold 3 > 2 pubkeys",
|
|
pubKeys: [][]byte{p2pkCompressedMain, p2pkCompressed2Main},
|
|
threshold: 3,
|
|
expected: "",
|
|
err: ErrTooManyRequiredSigs,
|
|
}, {
|
|
name: "threshold 2 > 1 pubkey",
|
|
pubKeys: [][]byte{p2pkCompressedMain},
|
|
threshold: 2,
|
|
expected: "",
|
|
err: ErrTooManyRequiredSigs,
|
|
}, {
|
|
name: "reject uncompressed pubkeys",
|
|
pubKeys: [][]byte{p2pkUncompressedMain},
|
|
threshold: 1,
|
|
expected: "",
|
|
err: ErrPubKeyType,
|
|
}}
|
|
|
|
for _, test := range tests {
|
|
script, err := MultiSigScriptV0(test.threshold, test.pubKeys...)
|
|
if !errors.Is(err, test.err) {
|
|
t.Errorf("%q: unexpected error - got %v, want %v", test.name, err,
|
|
test.err)
|
|
continue
|
|
}
|
|
|
|
const scriptVer = 0
|
|
expected := mustParseShortForm(scriptVer, test.expected)
|
|
if !bytes.Equal(script, expected) {
|
|
t.Errorf("%q: unexpected result -- got: %x\nwant: %x", test.name,
|
|
script, expected)
|
|
continue
|
|
}
|
|
}
|
|
}
|
|
|
|
// TestExtractStakeSubmissionPubKeyHashV0 ensures that extracting a public key
|
|
// hash from a version 0 stake submission pay-to-pubkey-hash script works as
|
|
// intended for all of the version 0 test scripts.
|
|
func TestExtractStakeSubmissionPubKeyHashV0(t *testing.T) {
|
|
for _, test := range scriptV0Tests {
|
|
// Determine the expected data based on the expected script type and
|
|
// data specified in the test.
|
|
var want []byte
|
|
if test.wantType == STStakeSubmissionPubKeyHash {
|
|
want = asByteSlice(t, test)
|
|
}
|
|
|
|
got := ExtractStakeSubmissionPubKeyHashV0(test.script)
|
|
if !bytes.Equal(got, want) {
|
|
t.Errorf("%q: unexpected pubkey hash -- got %x, want %x", test.name,
|
|
got, want)
|
|
continue
|
|
}
|
|
}
|
|
}
|
|
|
|
// TestExtractStakeSubmissionScriptHashV0 ensures that extracting a script hash
|
|
// from a version 0 stake submission pay-to-script-hash script works as intended
|
|
// for all of the version 0 test scripts.
|
|
func TestExtractStakeSubmissionScriptHashV0(t *testing.T) {
|
|
for _, test := range scriptV0Tests {
|
|
// Determine the expected data based on the expected script type and
|
|
// data specified in the test.
|
|
var want []byte
|
|
if test.wantType == STStakeSubmissionScriptHash {
|
|
want = asByteSlice(t, test)
|
|
}
|
|
|
|
got := ExtractStakeSubmissionScriptHashV0(test.script)
|
|
if !bytes.Equal(got, want) {
|
|
t.Errorf("%q: unexpected script hash -- got %x, want %x", test.name,
|
|
got, want)
|
|
continue
|
|
}
|
|
}
|
|
}
|
|
|
|
// TestExtractStakeGenPubKeyHashV0 ensures that extracting a public key
|
|
// hash from a version 0 stake generation pay-to-pubkey-hash script works as
|
|
// intended for all of the version 0 test scripts.
|
|
func TestExtractStakeGenPubKeyHashV0(t *testing.T) {
|
|
for _, test := range scriptV0Tests {
|
|
// Determine the expected data based on the expected script type and
|
|
// data specified in the test.
|
|
var want []byte
|
|
if test.wantType == STStakeGenPubKeyHash {
|
|
want = asByteSlice(t, test)
|
|
}
|
|
|
|
got := ExtractStakeGenPubKeyHashV0(test.script)
|
|
if !bytes.Equal(got, want) {
|
|
t.Errorf("%q: unexpected pubkey hash -- got %x, want %x", test.name,
|
|
got, want)
|
|
continue
|
|
}
|
|
}
|
|
}
|
|
|
|
// TestExtractStakeGenScriptHashV0 ensures that extracting a script hash
|
|
// from a version 0 stake generation pay-to-script-hash script works as intended
|
|
// for all of the version 0 test scripts.
|
|
func TestExtractStakeGenScriptHashV0(t *testing.T) {
|
|
for _, test := range scriptV0Tests {
|
|
// Determine the expected data based on the expected script type and
|
|
// data specified in the test.
|
|
var want []byte
|
|
if test.wantType == STStakeGenScriptHash {
|
|
want = asByteSlice(t, test)
|
|
}
|
|
|
|
got := ExtractStakeGenScriptHashV0(test.script)
|
|
if !bytes.Equal(got, want) {
|
|
t.Errorf("%q: unexpected script hash -- got %x, want %x", test.name,
|
|
got, want)
|
|
continue
|
|
}
|
|
}
|
|
}
|
|
|
|
// TestExtractStakeRevocationPubKeyHashV0 ensures that extracting a public key
|
|
// hash from a version 0 stake revocation pay-to-pubkey-hash script works as
|
|
// intended for all of the version 0 test scripts.
|
|
func TestExtractStakeRevocationPubKeyHashV0(t *testing.T) {
|
|
for _, test := range scriptV0Tests {
|
|
// Determine the expected data based on the expected script type and
|
|
// data specified in the test.
|
|
var want []byte
|
|
if test.wantType == STStakeRevocationPubKeyHash {
|
|
want = asByteSlice(t, test)
|
|
}
|
|
|
|
got := ExtractStakeRevocationPubKeyHashV0(test.script)
|
|
if !bytes.Equal(got, want) {
|
|
t.Errorf("%q: unexpected pubkey hash -- got %x, want %x", test.name,
|
|
got, want)
|
|
continue
|
|
}
|
|
}
|
|
}
|
|
|
|
// TestExtractStakeRevocationScriptHashV0 ensures that extracting a script hash
|
|
// from a version 0 stake revocation pay-to-script-hash script works as intended
|
|
// for all of the version 0 test scripts.
|
|
func TestExtractStakeRevocationScriptHashV0(t *testing.T) {
|
|
for _, test := range scriptV0Tests {
|
|
// Determine the expected data based on the expected script type and
|
|
// data specified in the test.
|
|
var want []byte
|
|
if test.wantType == STStakeRevocationScriptHash {
|
|
want = asByteSlice(t, test)
|
|
}
|
|
|
|
got := ExtractStakeRevocationScriptHashV0(test.script)
|
|
if !bytes.Equal(got, want) {
|
|
t.Errorf("%q: unexpected script hash -- got %x, want %x", test.name,
|
|
got, want)
|
|
continue
|
|
}
|
|
}
|
|
}
|
|
|
|
// TestExtractStakeChangePubKeyHashV0 ensures that extracting a public key hash
|
|
// from a version 0 stake change pay-to-pubkey-hash script works as intended for
|
|
// all of the version 0 test scripts.
|
|
func TestExtractStakeChangePubKeyHashV0(t *testing.T) {
|
|
for _, test := range scriptV0Tests {
|
|
// Determine the expected data based on the expected script type and
|
|
// data specified in the test.
|
|
var want []byte
|
|
if test.wantType == STStakeChangePubKeyHash {
|
|
want = asByteSlice(t, test)
|
|
}
|
|
|
|
got := ExtractStakeChangePubKeyHashV0(test.script)
|
|
if !bytes.Equal(got, want) {
|
|
t.Errorf("%q: unexpected pubkey hash -- got %x, want %x", test.name,
|
|
got, want)
|
|
continue
|
|
}
|
|
}
|
|
}
|
|
|
|
// TestExtractStakeChangeScriptHashV0 ensures that extracting a script hash from
|
|
// a version 0 stake change pay-to-script-hash script works as intended for all
|
|
// of the version 0 test scripts.
|
|
func TestExtractStakeChangeScriptHashV0(t *testing.T) {
|
|
for _, test := range scriptV0Tests {
|
|
// Determine the expected data based on the expected script type and
|
|
// data specified in the test.
|
|
var want []byte
|
|
if test.wantType == STStakeChangeScriptHash {
|
|
want = asByteSlice(t, test)
|
|
}
|
|
|
|
got := ExtractStakeChangeScriptHashV0(test.script)
|
|
if !bytes.Equal(got, want) {
|
|
t.Errorf("%q: unexpected script hash -- got %x, want %x", test.name,
|
|
got, want)
|
|
continue
|
|
}
|
|
}
|
|
}
|
|
|
|
// TestExtractTreasuryGenPubKeyHashV0 ensures that extracting a public key hash
|
|
// from a version 0 treasury generation pay-to-pubkey-hash script works as
|
|
// intended for all of the version 0 test scripts.
|
|
func TestExtractTreasuryGenPubKeyHashV0(t *testing.T) {
|
|
for _, test := range scriptV0Tests {
|
|
// Determine the expected data based on the expected script type and
|
|
// data specified in the test.
|
|
var want []byte
|
|
if test.wantType == STTreasuryGenPubKeyHash {
|
|
want = asByteSlice(t, test)
|
|
}
|
|
|
|
got := ExtractTreasuryGenPubKeyHashV0(test.script)
|
|
if !bytes.Equal(got, want) {
|
|
t.Errorf("%q: unexpected pubkey hash -- got %x, want %x", test.name,
|
|
got, want)
|
|
continue
|
|
}
|
|
}
|
|
}
|
|
|
|
// TestExtractTreasuryGenScriptHashV0 ensures that extracting a script hash from
|
|
// a version 0 treasury generation pay-to-script-hash script works as intended
|
|
// for all of the version 0 test scripts.
|
|
func TestExtractTreasuryGenScriptHashV0(t *testing.T) {
|
|
for _, test := range scriptV0Tests {
|
|
// Determine the expected data based on the expected script type and
|
|
// data specified in the test.
|
|
var want []byte
|
|
if test.wantType == STTreasuryGenScriptHash {
|
|
want = asByteSlice(t, test)
|
|
}
|
|
|
|
got := ExtractTreasuryGenScriptHashV0(test.script)
|
|
if !bytes.Equal(got, want) {
|
|
t.Errorf("%q: unexpected script hash -- got %x, want %x", test.name,
|
|
got, want)
|
|
continue
|
|
}
|
|
}
|
|
}
|
|
|
|
// TestExtractStakePubKeyHashV0 ensures that extracting a public key hash from
|
|
// the supported standard version 0 stake-tagged pay-to-pubkey-hash scripts
|
|
// works as intended for all of the version 0 test scripts.
|
|
func TestExtractStakePubKeyHashV0(t *testing.T) {
|
|
for _, test := range scriptV0Tests {
|
|
// Determine the expected data based on the expected script type and
|
|
// data specified in the test.
|
|
var want []byte
|
|
switch test.wantType {
|
|
case STStakeSubmissionPubKeyHash, STStakeGenPubKeyHash,
|
|
STStakeRevocationPubKeyHash, STStakeChangePubKeyHash,
|
|
STTreasuryGenPubKeyHash:
|
|
|
|
want = asByteSlice(t, test)
|
|
}
|
|
|
|
got := ExtractStakePubKeyHashV0(test.script)
|
|
if !bytes.Equal(got, want) {
|
|
t.Errorf("%q: unexpected script hash -- got %x, want %x", test.name,
|
|
got, want)
|
|
continue
|
|
}
|
|
}
|
|
}
|
|
|
|
// TestExtractStakeScriptHashV0 ensures that extracting a script hash from the
|
|
// supported standard version 0 stake-tagged pay-to-script-hash scripts works as
|
|
// intended for all of the version 0 test scripts.
|
|
func TestExtractStakeScriptHashV0(t *testing.T) {
|
|
for _, test := range scriptV0Tests {
|
|
// Determine the expected data based on the expected script type and
|
|
// data specified in the test.
|
|
var want []byte
|
|
switch test.wantType {
|
|
case STStakeSubmissionScriptHash, STStakeGenScriptHash,
|
|
STStakeRevocationScriptHash, STStakeChangeScriptHash,
|
|
STTreasuryGenScriptHash:
|
|
|
|
want = asByteSlice(t, test)
|
|
}
|
|
|
|
got := ExtractStakeScriptHashV0(test.script)
|
|
if !bytes.Equal(got, want) {
|
|
t.Errorf("%q: unexpected script hash -- got %x, want %x", test.name,
|
|
got, want)
|
|
continue
|
|
}
|
|
}
|
|
}
|
|
|
|
// TestProvablyPruneableScriptV0 ensures generating a version 0
|
|
// provably-pruneable nulldata script works as intended.
|
|
func TestProvablyPruneableScriptV0(t *testing.T) {
|
|
// Convenience function that closes over the script version and invokes
|
|
// mustParseShortForm to create more compact tests.
|
|
const scriptVersion = 0
|
|
p := func(format string, a ...interface{}) []byte {
|
|
return mustParseShortForm(scriptVersion, fmt.Sprintf(format, a...))
|
|
}
|
|
|
|
tests := []struct {
|
|
name string
|
|
data []byte
|
|
expected []byte
|
|
err error
|
|
typ ScriptType
|
|
}{{
|
|
name: "small int",
|
|
data: hexToBytes("01"),
|
|
expected: p("RETURN 1"),
|
|
err: nil,
|
|
typ: STNullData,
|
|
}, {
|
|
name: "max small int",
|
|
data: hexToBytes("10"),
|
|
expected: p("RETURN 16"),
|
|
err: nil,
|
|
typ: STNullData,
|
|
}, {
|
|
name: "data of size before OP_PUSHDATA1 is needed",
|
|
data: bytes.Repeat(hexToBytes("00"), 75),
|
|
expected: p("RETURN DATA_75 0x00{75}"),
|
|
err: nil,
|
|
typ: STNullData,
|
|
}, {
|
|
name: "one less than max allowed size",
|
|
data: bytes.Repeat(hexToBytes("00"), MaxDataCarrierSizeV0-1),
|
|
expected: p("RETURN PUSHDATA1 0xff 0x00{255}"),
|
|
err: nil,
|
|
typ: STNullData,
|
|
}, {
|
|
name: "max allowed size",
|
|
data: bytes.Repeat(hexToBytes("00"), MaxDataCarrierSizeV0),
|
|
expected: p("RETURN PUSHDATA2 0x0001 0x00{256}"),
|
|
err: nil,
|
|
typ: STNullData,
|
|
}, {
|
|
name: "too big",
|
|
data: bytes.Repeat(hexToBytes("00"), MaxDataCarrierSizeV0+1),
|
|
expected: nil,
|
|
err: ErrTooMuchNullData,
|
|
typ: STNonStandard,
|
|
}}
|
|
|
|
for _, test := range tests {
|
|
script, err := ProvablyPruneableScriptV0(test.data)
|
|
if !errors.Is(err, test.err) {
|
|
t.Errorf("%q: unexpected error - got %v, want %v", test.name, err,
|
|
test.err)
|
|
continue
|
|
}
|
|
|
|
// Ensure the expected script was generated.
|
|
if !bytes.Equal(script, test.expected) {
|
|
t.Errorf("%q: unexpected script -- got: %x, want: %x", test.name,
|
|
script, test.expected)
|
|
continue
|
|
}
|
|
|
|
// Ensure the script has the correct type.
|
|
scriptType := DetermineScriptType(scriptVersion, script)
|
|
if scriptType != test.typ {
|
|
t.Errorf("%q: unexpected script type -- got: %v, want: %v",
|
|
test.name, scriptType, test.typ)
|
|
continue
|
|
}
|
|
}
|
|
}
|
|
|
|
// expectedAtomicSwapDataV0 is a convenience function that converts the passed
|
|
// parameters into an expected version 0 atomic swap data pushes structure.
|
|
func expectedAtomicSwapDataV0(recipientHash, refundHash, secretHash string, secretSize, lockTime int64) *AtomicSwapDataPushesV0 {
|
|
result := &AtomicSwapDataPushesV0{
|
|
SecretSize: secretSize,
|
|
LockTime: lockTime,
|
|
}
|
|
copy(result.RecipientHash160[:], hexToBytes(recipientHash))
|
|
copy(result.RefundHash160[:], hexToBytes(refundHash))
|
|
copy(result.SecretHash[:], hexToBytes(secretHash))
|
|
return result
|
|
}
|
|
|
|
// TestExtractAtomicSwapDataPushesV0 ensures version 0 atomic swap scripts are
|
|
// recognized properly and the correct information is extracted from them.
|
|
func TestExtractAtomicSwapDataPushesV0(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
// Define some values shared in the tests for convenience.
|
|
secret := "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08"
|
|
recipient := "0000000000000000000000000000000000000001"
|
|
refund := "0000000000000000000000000000000000000002"
|
|
|
|
tests := []struct {
|
|
name string // test description
|
|
script string // script to analyze
|
|
data *AtomicSwapDataPushesV0 // expected data pushes
|
|
}{{
|
|
name: "normal valid atomic swap",
|
|
script: fmt.Sprintf("IF SIZE 32 EQUALVERIFY SHA256 DATA_32 0x%s "+
|
|
"EQUALVERIFY DUP HASH160 DATA_20 0x%s ELSE 300000 "+
|
|
"CHECKLOCKTIMEVERIFY DROP DUP HASH160 DATA_20 0x%s ENDIF "+
|
|
"EQUALVERIFY CHECKSIG", secret, recipient, refund),
|
|
data: expectedAtomicSwapDataV0(recipient, refund, secret, 32, 300000),
|
|
}, {
|
|
name: "atomic swap with mismatched smallint secret size",
|
|
script: fmt.Sprintf("IF SIZE 16 EQUALVERIFY SHA256 DATA_32 0x%s "+
|
|
"EQUALVERIFY DUP HASH160 DATA_20 0x%s ELSE 300000 "+
|
|
"CHECKLOCKTIMEVERIFY DROP DUP HASH160 DATA_20 0x%s ENDIF "+
|
|
"EQUALVERIFY CHECKSIG", secret, recipient, refund),
|
|
data: expectedAtomicSwapDataV0(recipient, refund, secret, 16, 300000),
|
|
}, {
|
|
name: "atomic swap with smallint locktime",
|
|
script: fmt.Sprintf("IF SIZE 32 EQUALVERIFY SHA256 DATA_32 0x%s "+
|
|
"EQUALVERIFY DUP HASH160 DATA_20 0x%s ELSE 10 CHECKLOCKTIMEVERIFY "+
|
|
"DROP DUP HASH160 DATA_20 0x%s ENDIF EQUALVERIFY CHECKSIG", secret,
|
|
recipient, refund),
|
|
data: expectedAtomicSwapDataV0(recipient, refund, secret, 32,
|
|
10),
|
|
}, {
|
|
name: "almost valid, but too many bytes for sha256 size",
|
|
script: fmt.Sprintf("IF SIZE 2147483649 EQUALVERIFY SHA256 DATA_32 "+
|
|
"0x%s EQUALVERIFY DUP HASH160 DATA_20 0x%s ELSE 300000 "+
|
|
"CHECKLOCKTIMEVERIFY DROP DUP HASH160 DATA_20 0x%s ENDIF "+
|
|
"EQUALVERIFY CHECKSIG", secret, recipient, refund),
|
|
data: nil,
|
|
}, {
|
|
name: "almost valid, but NOP for secret size",
|
|
script: fmt.Sprintf("IF SIZE NOP EQUALVERIFY SHA256 DATA_32 0x%s "+
|
|
"EQUALVERIFY DUP HASH160 DATA_20 0x%s ELSE 300000 "+
|
|
"CHECKLOCKTIMEVERIFY DROP DUP HASH160 DATA_20 0x%s ENDIF "+
|
|
"EQUALVERIFY CHECKSIG", secret, recipient, refund),
|
|
data: nil,
|
|
}, {
|
|
name: "almost valid, but NOP for locktime",
|
|
script: fmt.Sprintf("IF SIZE 32 EQUALVERIFY SHA256 DATA_32 0x%s "+
|
|
"EQUALVERIFY DUP HASH160 DATA_20 0x%s ELSE NOP CHECKLOCKTIMEVERIFY "+
|
|
"DROP DUP HASH160 DATA_20 0x%s ENDIF EQUALVERIFY CHECKSIG", secret,
|
|
recipient, refund),
|
|
data: nil,
|
|
}, {
|
|
name: "almost valid, but wrong sha256 secret size",
|
|
script: fmt.Sprintf("IF SIZE 32 EQUALVERIFY SHA256 DATA_31 0x%s "+
|
|
"EQUALVERIFY DUP HASH160 DATA_20 0x%s ELSE 300000 "+
|
|
"CHECKLOCKTIMEVERIFY DROP DUP HASH160 DATA_20 0x%s ENDIF "+
|
|
"EQUALVERIFY CHECKSIG", secret[:len(secret)-2], recipient, refund),
|
|
data: nil,
|
|
}, {
|
|
name: "almost valid, but wrong recipient hash size",
|
|
script: fmt.Sprintf("IF SIZE 32 EQUALVERIFY SHA256 DATA_32 0x%s "+
|
|
"EQUALVERIFY DUP HASH160 DATA_19 0x%s ELSE 300000 "+
|
|
"CHECKLOCKTIMEVERIFY DROP DUP HASH160 DATA_20 0x%s ENDIF "+
|
|
"EQUALVERIFY CHECKSIG", secret, recipient[:len(recipient)-2],
|
|
refund),
|
|
data: nil,
|
|
}, {
|
|
name: "almost valid, but wrong refund hash size",
|
|
script: fmt.Sprintf("IF SIZE 32 EQUALVERIFY SHA256 DATA_32 0x%s "+
|
|
"EQUALVERIFY DUP HASH160 DATA_20 0x%s ELSE 300000 "+
|
|
"CHECKLOCKTIMEVERIFY DROP DUP HASH160 DATA_19 0x%s ENDIF "+
|
|
"EQUALVERIFY CHECKSIG", secret, recipient, refund[:len(refund)-2]),
|
|
data: nil,
|
|
}, {
|
|
name: "almost valid, but missing final CHECKSIG",
|
|
script: fmt.Sprintf("IF SIZE 32 EQUALVERIFY SHA256 DATA_32 0x%s "+
|
|
"EQUALVERIFY DUP HASH160 DATA_20 0x%s ELSE 300000 "+
|
|
"CHECKLOCKTIMEVERIFY DROP DUP HASH160 DATA_20 0x%s ENDIF "+
|
|
"EQUALVERIFY", secret, recipient, refund),
|
|
data: nil,
|
|
}, {
|
|
name: "almost valid, but additional opcode at end",
|
|
script: fmt.Sprintf("IF SIZE 32 EQUALVERIFY SHA256 DATA_32 0x%s "+
|
|
"EQUALVERIFY DUP HASH160 DATA_20 0x%s ELSE 300000 "+
|
|
"CHECKLOCKTIMEVERIFY DROP DUP HASH160 DATA_20 0x%s ENDIF "+
|
|
"EQUALVERIFY CHECKSIG NOP", secret, recipient, refund),
|
|
data: nil,
|
|
}, {
|
|
name: "almost valid, but parse error",
|
|
script: fmt.Sprintf("IF SIZE 32 EQUALVERIFY SHA256 DATA_32 0x%s "+
|
|
"EQUALVERIFY DUP HASH160 DATA_20 0x%s ELSE 300000 "+
|
|
"CHECKLOCKTIMEVERIFY DROP DUP HASH160 DATA_24 0x%s ENDIF "+
|
|
"EQUALVERIFY CHECKSIG", secret, recipient, refund),
|
|
data: nil,
|
|
}}
|
|
|
|
const scriptVersion = 0
|
|
for _, test := range tests {
|
|
script := mustParseShortForm(scriptVersion, test.script)
|
|
|
|
// Attempt to extract the atomic swap data from the script and ensure
|
|
// there is either extracted data or not as expected.
|
|
data := ExtractAtomicSwapDataPushesV0(script)
|
|
switch {
|
|
case test.data == nil && data != nil:
|
|
t.Errorf("%q: unexpected extracted data", test.name)
|
|
continue
|
|
|
|
case test.data != nil && data == nil:
|
|
t.Errorf("%q: failed to extract expected data", test.name)
|
|
continue
|
|
|
|
case data == nil:
|
|
continue
|
|
}
|
|
|
|
// Ensure the individual fields of the extracted data is accurate. The
|
|
// two structs could be directly compared, but testing them individually
|
|
// allows nicer error reporting in the case of failure.
|
|
if data.RecipientHash160 != test.data.RecipientHash160 {
|
|
t.Errorf("%q: unexpected recipient hash -- got %x, want %x",
|
|
test.name, data.RecipientHash160, test.data.RecipientHash160)
|
|
continue
|
|
}
|
|
if data.RefundHash160 != test.data.RefundHash160 {
|
|
t.Errorf("%q: unexpected refund hash -- got %x, want %x", test.name,
|
|
data.RefundHash160, test.data.RefundHash160)
|
|
continue
|
|
}
|
|
if data.SecretHash != test.data.SecretHash {
|
|
t.Errorf("%q: unexpected secret hash -- got %x, want %x", test.name,
|
|
data.SecretHash, test.data.SecretHash)
|
|
continue
|
|
}
|
|
if data.SecretSize != test.data.SecretSize {
|
|
t.Errorf("%q: unexpected secret size -- got %d, want %d", test.name,
|
|
data.SecretSize, test.data.SecretSize)
|
|
continue
|
|
}
|
|
if data.LockTime != test.data.LockTime {
|
|
t.Errorf("%q: unexpected locktime -- got %d, want %d", test.name,
|
|
data.LockTime, test.data.LockTime)
|
|
continue
|
|
}
|
|
}
|
|
}
|