+++ /dev/null
-// Copyright (c) 2013-2017 The btcsuite developers
-// Use of this source code is governed by an ISC
-// license that can be found in the LICENSE file.
-
-package txscript
-
-import (
- "bytes"
- "encoding/hex"
- "encoding/json"
- "errors"
- "fmt"
- "io/ioutil"
- "strconv"
- "strings"
- "testing"
-
- "github.com/btcsuite/btcd/chaincfg/chainhash"
- "github.com/btcsuite/btcd/wire"
- "github.com/btcsuite/btcutil"
-)
-
-// scriptTestName returns a descriptive test name for the given reference script
-// test data.
-func scriptTestName(test []interface{}) (string, error) {
- // Account for any optional leading witness data.
- var witnessOffset int
- if _, ok := test[0].([]interface{}); ok {
- witnessOffset++
- }
-
- // In addition to the optional leading witness data, the test must
- // consist of at least a signature script, public key script, flags,
- // and expected error. Finally, it may optionally contain a comment.
- if len(test) < witnessOffset+4 || len(test) > witnessOffset+5 {
- return "", fmt.Errorf("invalid test length %d", len(test))
- }
-
- // Use the comment for the test name if one is specified, otherwise,
- // construct the name based on the signature script, public key script,
- // and flags.
- var name string
- if len(test) == witnessOffset+5 {
- name = fmt.Sprintf("test (%s)", test[witnessOffset+4])
- } else {
- name = fmt.Sprintf("test ([%s, %s, %s])", test[witnessOffset],
- test[witnessOffset+1], test[witnessOffset+2])
- }
- return name, nil
-}
-
-// parse hex string into a []byte.
-func parseHex(tok string) ([]byte, error) {
- if !strings.HasPrefix(tok, "0x") {
- return nil, errors.New("not a hex number")
- }
- return hex.DecodeString(tok[2:])
-}
-
-// parseWitnessStack parses a json array of witness items encoded as hex into a
-// slice of witness elements.
-func parseWitnessStack(elements []interface{}) ([][]byte, error) {
- witness := make([][]byte, len(elements))
- for i, e := range elements {
- witElement, err := hex.DecodeString(e.(string))
- if err != nil {
- return nil, err
- }
-
- witness[i] = witElement
- }
-
- return witness, nil
-}
-
-// shortFormOps holds a map of opcode names to values for use in short form
-// parsing. It is declared here so it only needs to be created once.
-var shortFormOps map[string]byte
-
-// parseShortForm parses a string as as used in the Bitcoin Core reference tests
-// into the script it came from.
-//
-// The format used for these tests is pretty simple if ad-hoc:
-// - Opcodes other than the push opcodes and unknown are present as
-// either OP_NAME or just NAME
-// - Plain numbers are made into push operations
-// - Numbers beginning with 0x are inserted into the []byte as-is (so
-// 0x14 is OP_DATA_20)
-// - Single quoted strings are pushed as data
-// - Anything else is an error
-func parseShortForm(script string) ([]byte, error) {
- // Only create the short form opcode map once.
- if shortFormOps == nil {
- ops := make(map[string]byte)
- for opcodeName, opcodeValue := range OpcodeByName {
- if strings.Contains(opcodeName, "OP_UNKNOWN") {
- continue
- }
- ops[opcodeName] = opcodeValue
-
- // The opcodes named OP_# can't have the OP_ prefix
- // stripped or they would conflict with the plain
- // numbers. Also, since OP_FALSE and OP_TRUE are
- // aliases for the OP_0, and OP_1, respectively, they
- // have the same value, so detect those by name and
- // allow them.
- if (opcodeName == "OP_FALSE" || opcodeName == "OP_TRUE") ||
- (opcodeValue != OP_0 && (opcodeValue < OP_1 ||
- opcodeValue > OP_16)) {
-
- ops[strings.TrimPrefix(opcodeName, "OP_")] = opcodeValue
- }
- }
- shortFormOps = ops
- }
-
- // Split only does one separator so convert all \n and tab into space.
- script = strings.Replace(script, "\n", " ", -1)
- script = strings.Replace(script, "\t", " ", -1)
- tokens := strings.Split(script, " ")
- builder := NewScriptBuilder()
-
- for _, tok := range tokens {
- if len(tok) == 0 {
- continue
- }
- // if parses as a plain number
- if num, err := strconv.ParseInt(tok, 10, 64); err == nil {
- builder.AddInt64(num)
- continue
- } else if bts, err := parseHex(tok); err == nil {
- // Concatenate the bytes manually since the test code
- // intentionally creates scripts that are too large and
- // would cause the builder to error otherwise.
- if builder.err == nil {
- builder.script = append(builder.script, bts...)
- }
- } else if len(tok) >= 2 &&
- tok[0] == '\'' && tok[len(tok)-1] == '\'' {
- builder.AddFullData([]byte(tok[1 : len(tok)-1]))
- } else if opcode, ok := shortFormOps[tok]; ok {
- builder.AddOp(opcode)
- } else {
- return nil, fmt.Errorf("bad token %q", tok)
- }
-
- }
- return builder.Script()
-}
-
-// parseScriptFlags parses the provided flags string from the format used in the
-// reference tests into ScriptFlags suitable for use in the script engine.
-func parseScriptFlags(flagStr string) (ScriptFlags, error) {
- var flags ScriptFlags
-
- sFlags := strings.Split(flagStr, ",")
- for _, flag := range sFlags {
- switch flag {
- case "":
- // Nothing.
- case "CHECKLOCKTIMEVERIFY":
- flags |= ScriptVerifyCheckLockTimeVerify
- case "CHECKSEQUENCEVERIFY":
- flags |= ScriptVerifyCheckSequenceVerify
- case "CLEANSTACK":
- flags |= ScriptVerifyCleanStack
- case "DERSIG":
- flags |= ScriptVerifyDERSignatures
- case "DISCOURAGE_UPGRADABLE_NOPS":
- flags |= ScriptDiscourageUpgradableNops
- case "LOW_S":
- flags |= ScriptVerifyLowS
- case "MINIMALDATA":
- flags |= ScriptVerifyMinimalData
- case "NONE":
- // Nothing.
- case "NULLDUMMY":
- flags |= ScriptStrictMultiSig
- case "NULLFAIL":
- flags |= ScriptVerifyNullFail
- case "P2SH":
- flags |= ScriptBip16
- case "SIGPUSHONLY":
- flags |= ScriptVerifySigPushOnly
- case "STRICTENC":
- flags |= ScriptVerifyStrictEncoding
- case "WITNESS":
- flags |= ScriptVerifyWitness
- case "DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM":
- flags |= ScriptVerifyDiscourageUpgradeableWitnessProgram
- case "MINIMALIF":
- flags |= ScriptVerifyMinimalIf
- case "WITNESS_PUBKEYTYPE":
- flags |= ScriptVerifyWitnessPubKeyType
- default:
- return flags, fmt.Errorf("invalid flag: %s", flag)
- }
- }
- return flags, nil
-}
-
-// parseExpectedResult parses the provided expected result string into allowed
-// script error codes. An error is returned if the expected result string is
-// not supported.
-func parseExpectedResult(expected string) ([]ErrorCode, error) {
- switch expected {
- case "OK":
- return nil, nil
- case "UNKNOWN_ERROR":
- return []ErrorCode{ErrNumberTooBig, ErrMinimalData}, nil
- case "PUBKEYTYPE":
- return []ErrorCode{ErrPubKeyType}, nil
- case "SIG_DER":
- return []ErrorCode{ErrSigDER, ErrInvalidSigHashType}, nil
- case "EVAL_FALSE":
- return []ErrorCode{ErrEvalFalse, ErrEmptyStack}, nil
- case "EQUALVERIFY":
- return []ErrorCode{ErrEqualVerify}, nil
- case "NULLFAIL":
- return []ErrorCode{ErrNullFail}, nil
- case "SIG_HIGH_S":
- return []ErrorCode{ErrSigHighS}, nil
- case "SIG_HASHTYPE":
- return []ErrorCode{ErrInvalidSigHashType}, nil
- case "SIG_NULLDUMMY":
- return []ErrorCode{ErrSigNullDummy}, nil
- case "SIG_PUSHONLY":
- return []ErrorCode{ErrNotPushOnly}, nil
- case "CLEANSTACK":
- return []ErrorCode{ErrCleanStack}, nil
- case "BAD_OPCODE":
- return []ErrorCode{ErrReservedOpcode, ErrMalformedPush}, nil
- case "UNBALANCED_CONDITIONAL":
- return []ErrorCode{ErrUnbalancedConditional,
- ErrInvalidStackOperation}, nil
- case "OP_RETURN":
- return []ErrorCode{ErrEarlyReturn}, nil
- case "VERIFY":
- return []ErrorCode{ErrVerify}, nil
- case "INVALID_STACK_OPERATION", "INVALID_ALTSTACK_OPERATION":
- return []ErrorCode{ErrInvalidStackOperation}, nil
- case "DISABLED_OPCODE":
- return []ErrorCode{ErrDisabledOpcode}, nil
- case "DISCOURAGE_UPGRADABLE_NOPS":
- return []ErrorCode{ErrDiscourageUpgradableNOPs}, nil
- case "PUSH_SIZE":
- return []ErrorCode{ErrElementTooBig}, nil
- case "OP_COUNT":
- return []ErrorCode{ErrTooManyOperations}, nil
- case "STACK_SIZE":
- return []ErrorCode{ErrStackOverflow}, nil
- case "SCRIPT_SIZE":
- return []ErrorCode{ErrScriptTooBig}, nil
- case "PUBKEY_COUNT":
- return []ErrorCode{ErrInvalidPubKeyCount}, nil
- case "SIG_COUNT":
- return []ErrorCode{ErrInvalidSignatureCount}, nil
- case "MINIMALDATA":
- return []ErrorCode{ErrMinimalData}, nil
- case "NEGATIVE_LOCKTIME":
- return []ErrorCode{ErrNegativeLockTime}, nil
- case "UNSATISFIED_LOCKTIME":
- return []ErrorCode{ErrUnsatisfiedLockTime}, nil
- case "MINIMALIF":
- return []ErrorCode{ErrMinimalIf}, nil
- case "DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM":
- return []ErrorCode{ErrDiscourageUpgradableWitnessProgram}, nil
- case "WITNESS_PROGRAM_WRONG_LENGTH":
- return []ErrorCode{ErrWitnessProgramWrongLength}, nil
- case "WITNESS_PROGRAM_WITNESS_EMPTY":
- return []ErrorCode{ErrWitnessProgramEmpty}, nil
- case "WITNESS_PROGRAM_MISMATCH":
- return []ErrorCode{ErrWitnessProgramMismatch}, nil
- case "WITNESS_MALLEATED":
- return []ErrorCode{ErrWitnessMalleated}, nil
- case "WITNESS_MALLEATED_P2SH":
- return []ErrorCode{ErrWitnessMalleatedP2SH}, nil
- case "WITNESS_UNEXPECTED":
- return []ErrorCode{ErrWitnessUnexpected}, nil
- case "WITNESS_PUBKEYTYPE":
- return []ErrorCode{ErrWitnessPubKeyType}, nil
- }
-
- return nil, fmt.Errorf("unrecognized expected result in test data: %v",
- expected)
-}
-
-// createSpendTx generates a basic spending transaction given the passed
-// signature, witness and public key scripts.
-func createSpendingTx(witness [][]byte, sigScript, pkScript []byte,
- outputValue int64) *wire.MsgTx {
-
- coinbaseTx := wire.NewMsgTx(wire.TxVersion)
-
- outPoint := wire.NewOutPoint(&chainhash.Hash{}, ^uint32(0))
- txIn := wire.NewTxIn(outPoint, []byte{OP_0, OP_0}, nil)
- txOut := wire.NewTxOut(outputValue, pkScript)
- coinbaseTx.AddTxIn(txIn)
- coinbaseTx.AddTxOut(txOut)
-
- spendingTx := wire.NewMsgTx(wire.TxVersion)
- coinbaseTxSha := coinbaseTx.TxHash()
- outPoint = wire.NewOutPoint(&coinbaseTxSha, 0)
- txIn = wire.NewTxIn(outPoint, sigScript, witness)
- txOut = wire.NewTxOut(outputValue, nil)
-
- spendingTx.AddTxIn(txIn)
- spendingTx.AddTxOut(txOut)
-
- return spendingTx
-}
-
-// scriptWithInputVal wraps a target pkScript with the value of the output in
-// which it is contained. The inputVal is necessary in order to properly
-// validate inputs which spend nested, or native witness programs.
-type scriptWithInputVal struct {
- inputVal int64
- pkScript []byte
-}
-
-// testScripts ensures all of the passed script tests execute with the expected
-// results with or without using a signature cache, as specified by the
-// parameter.
-func testScripts(t *testing.T, tests [][]interface{}, useSigCache bool) {
- // Create a signature cache to use only if requested.
- var sigCache *SigCache
- if useSigCache {
- sigCache = NewSigCache(10)
- }
-
- for i, test := range tests {
- // "Format is: [[wit..., amount]?, scriptSig, scriptPubKey,
- // flags, expected_scripterror, ... comments]"
-
- // Skip single line comments.
- if len(test) == 1 {
- continue
- }
-
- // Construct a name for the test based on the comment and test
- // data.
- name, err := scriptTestName(test)
- if err != nil {
- t.Errorf("TestScripts: invalid test #%d: %v", i, err)
- continue
- }
-
- var (
- witness wire.TxWitness
- inputAmt btcutil.Amount
- )
-
- // When the first field of the test data is a slice it contains
- // witness data and everything else is offset by 1 as a result.
- witnessOffset := 0
- if witnessData, ok := test[0].([]interface{}); ok {
- witnessOffset++
-
- // If this is a witness test, then the final element
- // within the slice is the input amount, so we ignore
- // all but the last element in order to parse the
- // witness stack.
- strWitnesses := witnessData[:len(witnessData)-1]
- witness, err = parseWitnessStack(strWitnesses)
- if err != nil {
- t.Errorf("%s: can't parse witness; %v", name, err)
- continue
- }
-
- inputAmt, err = btcutil.NewAmount(witnessData[len(witnessData)-1].(float64))
- if err != nil {
- t.Errorf("%s: can't parse input amt: %v",
- name, err)
- continue
- }
-
- }
-
- // Extract and parse the signature script from the test fields.
- scriptSigStr, ok := test[witnessOffset].(string)
- if !ok {
- t.Errorf("%s: signature script is not a string", name)
- continue
- }
- scriptSig, err := parseShortForm(scriptSigStr)
- if err != nil {
- t.Errorf("%s: can't parse signature script: %v", name,
- err)
- continue
- }
-
- // Extract and parse the public key script from the test fields.
- scriptPubKeyStr, ok := test[witnessOffset+1].(string)
- if !ok {
- t.Errorf("%s: public key script is not a string", name)
- continue
- }
- scriptPubKey, err := parseShortForm(scriptPubKeyStr)
- if err != nil {
- t.Errorf("%s: can't parse public key script: %v", name,
- err)
- continue
- }
-
- // Extract and parse the script flags from the test fields.
- flagsStr, ok := test[witnessOffset+2].(string)
- if !ok {
- t.Errorf("%s: flags field is not a string", name)
- continue
- }
- flags, err := parseScriptFlags(flagsStr)
- if err != nil {
- t.Errorf("%s: %v", name, err)
- continue
- }
-
- // Extract and parse the expected result from the test fields.
- //
- // Convert the expected result string into the allowed script
- // error codes. This is necessary because txscript is more
- // fine grained with its errors than the reference test data, so
- // some of the reference test data errors map to more than one
- // possibility.
- resultStr, ok := test[witnessOffset+3].(string)
- if !ok {
- t.Errorf("%s: result field is not a string", name)
- continue
- }
- allowedErrorCodes, err := parseExpectedResult(resultStr)
- if err != nil {
- t.Errorf("%s: %v", name, err)
- continue
- }
-
- // Generate a transaction pair such that one spends from the
- // other and the provided signature and public key scripts are
- // used, then create a new engine to execute the scripts.
- tx := createSpendingTx(witness, scriptSig, scriptPubKey,
- int64(inputAmt))
- vm, err := NewEngine(scriptPubKey, tx, 0, flags, sigCache, nil,
- int64(inputAmt))
- if err == nil {
- err = vm.Execute()
- }
-
- // Ensure there were no errors when the expected result is OK.
- if resultStr == "OK" {
- if err != nil {
- t.Errorf("%s failed to execute: %v", name, err)
- }
- continue
- }
-
- // At this point an error was expected so ensure the result of
- // the execution matches it.
- success := false
- for _, code := range allowedErrorCodes {
- if IsErrorCode(err, code) {
- success = true
- break
- }
- }
- if !success {
- if serr, ok := err.(Error); ok {
- t.Errorf("%s: want error codes %v, got %v", name,
- allowedErrorCodes, serr.ErrorCode)
- continue
- }
- t.Errorf("%s: want error codes %v, got err: %v (%T)",
- name, allowedErrorCodes, err, err)
- continue
- }
- }
-}
-
-// TestScripts ensures all of the tests in script_tests.json execute with the
-// expected results as defined in the test data.
-func TestScripts(t *testing.T) {
- file, err := ioutil.ReadFile("data/script_tests.json")
- if err != nil {
- t.Fatalf("TestScripts: %v\n", err)
- }
-
- var tests [][]interface{}
- err = json.Unmarshal(file, &tests)
- if err != nil {
- t.Fatalf("TestScripts couldn't Unmarshal: %v", err)
- }
-
- // Run all script tests with and without the signature cache.
- testScripts(t, tests, true)
- testScripts(t, tests, false)
-}
-
-// testVecF64ToUint32 properly handles conversion of float64s read from the JSON
-// test data to unsigned 32-bit integers. This is necessary because some of the
-// test data uses -1 as a shortcut to mean max uint32 and direct conversion of a
-// negative float to an unsigned int is implementation dependent and therefore
-// doesn't result in the expected value on all platforms. This function woks
-// around that limitation by converting to a 32-bit signed integer first and
-// then to a 32-bit unsigned integer which results in the expected behavior on
-// all platforms.
-func testVecF64ToUint32(f float64) uint32 {
- return uint32(int32(f))
-}
-
-// TestTxInvalidTests ensures all of the tests in tx_invalid.json fail as
-// expected.
-func TestTxInvalidTests(t *testing.T) {
- file, err := ioutil.ReadFile("data/tx_invalid.json")
- if err != nil {
- t.Fatalf("TestTxInvalidTests: %v\n", err)
- }
-
- var tests [][]interface{}
- err = json.Unmarshal(file, &tests)
- if err != nil {
- t.Fatalf("TestTxInvalidTests couldn't Unmarshal: %v\n", err)
- }
-
- // form is either:
- // ["this is a comment "]
- // or:
- // [[[previous hash, previous index, previous scriptPubKey]...,]
- // serializedTransaction, verifyFlags]
-testloop:
- for i, test := range tests {
- inputs, ok := test[0].([]interface{})
- if !ok {
- continue
- }
-
- if len(test) != 3 {
- t.Errorf("bad test (bad length) %d: %v", i, test)
- continue
-
- }
- serializedhex, ok := test[1].(string)
- if !ok {
- t.Errorf("bad test (arg 2 not string) %d: %v", i, test)
- continue
- }
- serializedTx, err := hex.DecodeString(serializedhex)
- if err != nil {
- t.Errorf("bad test (arg 2 not hex %v) %d: %v", err, i,
- test)
- continue
- }
-
- tx, err := btcutil.NewTxFromBytes(serializedTx)
- if err != nil {
- t.Errorf("bad test (arg 2 not msgtx %v) %d: %v", err,
- i, test)
- continue
- }
-
- verifyFlags, ok := test[2].(string)
- if !ok {
- t.Errorf("bad test (arg 3 not string) %d: %v", i, test)
- continue
- }
-
- flags, err := parseScriptFlags(verifyFlags)
- if err != nil {
- t.Errorf("bad test %d: %v", i, err)
- continue
- }
-
- prevOuts := make(map[wire.OutPoint]scriptWithInputVal)
- for j, iinput := range inputs {
- input, ok := iinput.([]interface{})
- if !ok {
- t.Errorf("bad test (%dth input not array)"+
- "%d: %v", j, i, test)
- continue testloop
- }
-
- if len(input) < 3 || len(input) > 4 {
- t.Errorf("bad test (%dth input wrong length)"+
- "%d: %v", j, i, test)
- continue testloop
- }
-
- previoustx, ok := input[0].(string)
- if !ok {
- t.Errorf("bad test (%dth input hash not string)"+
- "%d: %v", j, i, test)
- continue testloop
- }
-
- prevhash, err := chainhash.NewHashFromStr(previoustx)
- if err != nil {
- t.Errorf("bad test (%dth input hash not hash %v)"+
- "%d: %v", j, err, i, test)
- continue testloop
- }
-
- idxf, ok := input[1].(float64)
- if !ok {
- t.Errorf("bad test (%dth input idx not number)"+
- "%d: %v", j, i, test)
- continue testloop
- }
- idx := testVecF64ToUint32(idxf)
-
- oscript, ok := input[2].(string)
- if !ok {
- t.Errorf("bad test (%dth input script not "+
- "string) %d: %v", j, i, test)
- continue testloop
- }
-
- script, err := parseShortForm(oscript)
- if err != nil {
- t.Errorf("bad test (%dth input script doesn't "+
- "parse %v) %d: %v", j, err, i, test)
- continue testloop
- }
-
- var inputValue float64
- if len(input) == 4 {
- inputValue, ok = input[3].(float64)
- if !ok {
- t.Errorf("bad test (%dth input value not int) "+
- "%d: %v", j, i, test)
- continue
- }
- }
-
- v := scriptWithInputVal{
- inputVal: int64(inputValue),
- pkScript: script,
- }
- prevOuts[*wire.NewOutPoint(prevhash, idx)] = v
- }
-
- for k, txin := range tx.MsgTx().TxIn {
- prevOut, ok := prevOuts[txin.PreviousOutPoint]
- if !ok {
- t.Errorf("bad test (missing %dth input) %d:%v",
- k, i, test)
- continue testloop
- }
- // These are meant to fail, so as soon as the first
- // input fails the transaction has failed. (some of the
- // test txns have good inputs, too..
- vm, err := NewEngine(prevOut.pkScript, tx.MsgTx(), k,
- flags, nil, nil, prevOut.inputVal)
- if err != nil {
- continue testloop
- }
-
- err = vm.Execute()
- if err != nil {
- continue testloop
- }
-
- }
- t.Errorf("test (%d:%v) succeeded when should fail",
- i, test)
- }
-}
-
-// TestTxValidTests ensures all of the tests in tx_valid.json pass as expected.
-func TestTxValidTests(t *testing.T) {
- file, err := ioutil.ReadFile("data/tx_valid.json")
- if err != nil {
- t.Fatalf("TestTxValidTests: %v\n", err)
- }
-
- var tests [][]interface{}
- err = json.Unmarshal(file, &tests)
- if err != nil {
- t.Fatalf("TestTxValidTests couldn't Unmarshal: %v\n", err)
- }
-
- // form is either:
- // ["this is a comment "]
- // or:
- // [[[previous hash, previous index, previous scriptPubKey, input value]...,]
- // serializedTransaction, verifyFlags]
-testloop:
- for i, test := range tests {
- inputs, ok := test[0].([]interface{})
- if !ok {
- continue
- }
-
- if len(test) != 3 {
- t.Errorf("bad test (bad length) %d: %v", i, test)
- continue
- }
- serializedhex, ok := test[1].(string)
- if !ok {
- t.Errorf("bad test (arg 2 not string) %d: %v", i, test)
- continue
- }
- serializedTx, err := hex.DecodeString(serializedhex)
- if err != nil {
- t.Errorf("bad test (arg 2 not hex %v) %d: %v", err, i,
- test)
- continue
- }
-
- tx, err := btcutil.NewTxFromBytes(serializedTx)
- if err != nil {
- t.Errorf("bad test (arg 2 not msgtx %v) %d: %v", err,
- i, test)
- continue
- }
-
- verifyFlags, ok := test[2].(string)
- if !ok {
- t.Errorf("bad test (arg 3 not string) %d: %v", i, test)
- continue
- }
-
- flags, err := parseScriptFlags(verifyFlags)
- if err != nil {
- t.Errorf("bad test %d: %v", i, err)
- continue
- }
-
- prevOuts := make(map[wire.OutPoint]scriptWithInputVal)
- for j, iinput := range inputs {
- input, ok := iinput.([]interface{})
- if !ok {
- t.Errorf("bad test (%dth input not array)"+
- "%d: %v", j, i, test)
- continue
- }
-
- if len(input) < 3 || len(input) > 4 {
- t.Errorf("bad test (%dth input wrong length)"+
- "%d: %v", j, i, test)
- continue
- }
-
- previoustx, ok := input[0].(string)
- if !ok {
- t.Errorf("bad test (%dth input hash not string)"+
- "%d: %v", j, i, test)
- continue
- }
-
- prevhash, err := chainhash.NewHashFromStr(previoustx)
- if err != nil {
- t.Errorf("bad test (%dth input hash not hash %v)"+
- "%d: %v", j, err, i, test)
- continue
- }
-
- idxf, ok := input[1].(float64)
- if !ok {
- t.Errorf("bad test (%dth input idx not number)"+
- "%d: %v", j, i, test)
- continue
- }
- idx := testVecF64ToUint32(idxf)
-
- oscript, ok := input[2].(string)
- if !ok {
- t.Errorf("bad test (%dth input script not "+
- "string) %d: %v", j, i, test)
- continue
- }
-
- script, err := parseShortForm(oscript)
- if err != nil {
- t.Errorf("bad test (%dth input script doesn't "+
- "parse %v) %d: %v", j, err, i, test)
- continue
- }
-
- var inputValue float64
- if len(input) == 4 {
- inputValue, ok = input[3].(float64)
- if !ok {
- t.Errorf("bad test (%dth input value not int) "+
- "%d: %v", j, i, test)
- continue
- }
- }
-
- v := scriptWithInputVal{
- inputVal: int64(inputValue),
- pkScript: script,
- }
- prevOuts[*wire.NewOutPoint(prevhash, idx)] = v
- }
-
- for k, txin := range tx.MsgTx().TxIn {
- prevOut, ok := prevOuts[txin.PreviousOutPoint]
- if !ok {
- t.Errorf("bad test (missing %dth input) %d:%v",
- k, i, test)
- continue testloop
- }
- vm, err := NewEngine(prevOut.pkScript, tx.MsgTx(), k,
- flags, nil, nil, prevOut.inputVal)
- if err != nil {
- t.Errorf("test (%d:%v:%d) failed to create "+
- "script: %v", i, test, k, err)
- continue
- }
-
- err = vm.Execute()
- if err != nil {
- t.Errorf("test (%d:%v:%d) failed to execute: "+
- "%v", i, test, k, err)
- continue
- }
- }
- }
-}
-
-// TestCalcSignatureHash runs the Bitcoin Core signature hash calculation tests
-// in sighash.json.
-// https://github.com/bitcoin/bitcoin/blob/master/src/test/data/sighash.json
-func TestCalcSignatureHash(t *testing.T) {
- file, err := ioutil.ReadFile("data/sighash.json")
- if err != nil {
- t.Fatalf("TestCalcSignatureHash: %v\n", err)
- }
-
- var tests [][]interface{}
- err = json.Unmarshal(file, &tests)
- if err != nil {
- t.Fatalf("TestCalcSignatureHash couldn't Unmarshal: %v\n",
- err)
- }
-
- for i, test := range tests {
- if i == 0 {
- // Skip first line -- contains comments only.
- continue
- }
- if len(test) != 5 {
- t.Fatalf("TestCalcSignatureHash: Test #%d has "+
- "wrong length.", i)
- }
- var tx wire.MsgTx
- rawTx, _ := hex.DecodeString(test[0].(string))
- err := tx.Deserialize(bytes.NewReader(rawTx))
- if err != nil {
- t.Errorf("TestCalcSignatureHash failed test #%d: "+
- "Failed to parse transaction: %v", i, err)
- continue
- }
-
- subScript, _ := hex.DecodeString(test[1].(string))
- parsedScript, err := parseScript(subScript)
- if err != nil {
- t.Errorf("TestCalcSignatureHash failed test #%d: "+
- "Failed to parse sub-script: %v", i, err)
- continue
- }
-
- hashType := SigHashType(testVecF64ToUint32(test[3].(float64)))
- hash := calcSignatureHash(parsedScript, hashType, &tx,
- int(test[2].(float64)))
-
- expectedHash, _ := chainhash.NewHashFromStr(test[4].(string))
- if !bytes.Equal(hash, expectedHash[:]) {
- t.Errorf("TestCalcSignatureHash failed test #%d: "+
- "Signature hash mismatch.", i)
- }
- }
-}