123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885 |
- // Copyright (c) 2013-2017 The btcsuite developers
- // Copyright (c) 2019 Caleb James DeLisle
- // 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"
- "fmt"
- "io/ioutil"
- "strconv"
- "strings"
- "testing"
- jsoniter "github.com/json-iterator/go"
- "github.com/pkt-cash/pktd/btcutil/er"
- "github.com/pkt-cash/pktd/txscript/opcode"
- "github.com/pkt-cash/pktd/txscript/params"
- "github.com/pkt-cash/pktd/txscript/parsescript"
- "github.com/pkt-cash/pktd/txscript/scriptbuilder"
- "github.com/pkt-cash/pktd/txscript/txscripterr"
- "github.com/pkt-cash/pktd/wire/constants"
- "github.com/pkt-cash/pktd/btcutil"
- "github.com/pkt-cash/pktd/chaincfg/chainhash"
- "github.com/pkt-cash/pktd/chaincfg/globalcfg"
- "github.com/pkt-cash/pktd/wire"
- )
- // scriptTestName returns a descriptive test name for the given reference script
- // test data.
- func scriptTestName(test []interface{}) (string, er.R) {
- // 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 "", er.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, er.R) {
- if !strings.HasPrefix(tok, "0x") {
- return nil, er.New("not a hex number")
- }
- x, e := hex.DecodeString(tok[2:])
- return x, er.E(e)
- }
- // parseWitnessStack parses a json array of witness items encoded as hex into a
- // slice of witness elements.
- func parseWitnessStack(elements []interface{}) ([][]byte, er.R) {
- witness := make([][]byte, len(elements))
- for i, e := range elements {
- witElement, err := hex.DecodeString(e.(string))
- if err != nil {
- return nil, er.E(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, er.R) {
- // 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 != opcode.OP_0 && (opcodeValue < opcode.OP_1 ||
- opcodeValue > opcode.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.ReplaceAll(script, "\n", " ")
- script = strings.ReplaceAll(script, "\t", " ")
- tokens := strings.Split(script, " ")
- builder := scriptbuilder.NewScriptBuilder()
- for _, tok := range tokens {
- if tok == "" {
- 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.ErrInt == nil {
- builder.ScriptInt = append(builder.ScriptInt, 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, er.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, er.R) {
- 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, er.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) ([]*er.ErrorCode, er.R) {
- switch expected {
- case "OK":
- return nil, nil
- case "UNKNOWN_ERROR":
- return []*er.ErrorCode{txscripterr.ErrNumberTooBig, txscripterr.ErrMinimalData}, nil
- case "PUBKEYTYPE":
- return []*er.ErrorCode{txscripterr.ErrPubKeyType}, nil
- case "SIG_DER":
- return []*er.ErrorCode{
- txscripterr.ErrSigTooShort, txscripterr.ErrSigTooLong,
- txscripterr.ErrSigInvalidSeqID, txscripterr.ErrSigInvalidDataLen, txscripterr.ErrSigMissingSTypeID,
- txscripterr.ErrSigMissingSLen, txscripterr.ErrSigInvalidSLen,
- txscripterr.ErrSigInvalidRIntID, txscripterr.ErrSigZeroRLen, txscripterr.ErrSigNegativeR,
- txscripterr.ErrSigTooMuchRPadding, txscripterr.ErrSigInvalidSIntID,
- txscripterr.ErrSigZeroSLen, txscripterr.ErrSigNegativeS, txscripterr.ErrSigTooMuchSPadding,
- txscripterr.ErrInvalidSigHashType,
- }, nil
- case "EVAL_FALSE":
- return []*er.ErrorCode{txscripterr.ErrEvalFalse, txscripterr.ErrEmptyStack}, nil
- case "EQUALVERIFY":
- return []*er.ErrorCode{txscripterr.ErrEqualVerify}, nil
- case "NULLFAIL":
- return []*er.ErrorCode{txscripterr.ErrNullFail}, nil
- case "SIG_HIGH_S":
- return []*er.ErrorCode{txscripterr.ErrSigHighS}, nil
- case "SIG_HASHTYPE":
- return []*er.ErrorCode{txscripterr.ErrInvalidSigHashType}, nil
- case "SIG_NULLDUMMY":
- return []*er.ErrorCode{txscripterr.ErrSigNullDummy}, nil
- case "SIG_PUSHONLY":
- return []*er.ErrorCode{txscripterr.ErrNotPushOnly}, nil
- case "CLEANSTACK":
- return []*er.ErrorCode{txscripterr.ErrCleanStack}, nil
- case "BAD_OPCODE":
- return []*er.ErrorCode{txscripterr.ErrReservedOpcode, txscripterr.ErrMalformedPush}, nil
- case "UNBALANCED_CONDITIONAL":
- return []*er.ErrorCode{
- txscripterr.ErrUnbalancedConditional,
- txscripterr.ErrInvalidStackOperation,
- }, nil
- case "OP_RETURN":
- return []*er.ErrorCode{txscripterr.ErrEarlyReturn}, nil
- case "VERIFY":
- return []*er.ErrorCode{txscripterr.ErrVerify}, nil
- case "INVALID_STACK_OPERATION", "INVALID_ALTSTACK_OPERATION":
- return []*er.ErrorCode{txscripterr.ErrInvalidStackOperation}, nil
- case "DISABLED_OPCODE":
- return []*er.ErrorCode{txscripterr.ErrDisabledOpcode}, nil
- case "DISCOURAGE_UPGRADABLE_NOPS":
- return []*er.ErrorCode{txscripterr.ErrDiscourageUpgradableNOPs}, nil
- case "PUSH_SIZE":
- return []*er.ErrorCode{txscripterr.ErrElementTooBig}, nil
- case "OP_COUNT":
- return []*er.ErrorCode{txscripterr.ErrTooManyOperations}, nil
- case "STACK_SIZE":
- return []*er.ErrorCode{txscripterr.ErrStackOverflow}, nil
- case "SCRIPT_SIZE":
- return []*er.ErrorCode{txscripterr.ErrScriptTooBig}, nil
- case "PUBKEY_COUNT":
- return []*er.ErrorCode{txscripterr.ErrInvalidPubKeyCount}, nil
- case "SIG_COUNT":
- return []*er.ErrorCode{txscripterr.ErrInvalidSignatureCount}, nil
- case "MINIMALDATA":
- return []*er.ErrorCode{txscripterr.ErrMinimalData}, nil
- case "NEGATIVE_LOCKTIME":
- return []*er.ErrorCode{txscripterr.ErrNegativeLockTime}, nil
- case "UNSATISFIED_LOCKTIME":
- return []*er.ErrorCode{txscripterr.ErrUnsatisfiedLockTime}, nil
- case "MINIMALIF":
- return []*er.ErrorCode{txscripterr.ErrMinimalIf}, nil
- case "DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM":
- return []*er.ErrorCode{txscripterr.ErrDiscourageUpgradableWitnessProgram}, nil
- case "WITNESS_PROGRAM_WRONG_LENGTH":
- return []*er.ErrorCode{txscripterr.ErrWitnessProgramWrongLength}, nil
- case "WITNESS_PROGRAM_WITNESS_EMPTY":
- return []*er.ErrorCode{txscripterr.ErrWitnessProgramEmpty}, nil
- case "WITNESS_PROGRAM_MISMATCH":
- return []*er.ErrorCode{txscripterr.ErrWitnessProgramMismatch}, nil
- case "WITNESS_MALLEATED":
- return []*er.ErrorCode{txscripterr.ErrWitnessMalleated}, nil
- case "WITNESS_MALLEATED_P2SH":
- return []*er.ErrorCode{txscripterr.ErrWitnessMalleatedP2SH}, nil
- case "WITNESS_UNEXPECTED":
- return []*er.ErrorCode{txscripterr.ErrWitnessUnexpected}, nil
- case "WITNESS_PUBKEYTYPE":
- return []*er.ErrorCode{txscripterr.ErrWitnessPubKeyType}, nil
- }
- return nil, er.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(constants.TxVersion)
- outPoint := wire.NewOutPoint(&chainhash.Hash{}, ^uint32(0))
- txIn := wire.NewTxIn(outPoint, []byte{opcode.OP_0, opcode.OP_0}, nil)
- txOut := wire.NewTxOut(outputValue, pkScript)
- coinbaseTx.AddTxIn(txIn)
- coinbaseTx.AddTxOut(txOut)
- spendingTx := wire.NewMsgTx(constants.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
- }
- ia, err := globalcfg.NewAmount(witnessData[len(witnessData)-1].(float64))
- if err != nil {
- t.Errorf("%s: can't parse input amt: %v",
- name, err)
- continue
- }
- inputAmt = btcutil.Amount(ia)
- }
- // 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 code.Is(err) {
- success = true
- break
- }
- }
- if !success {
- 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 = jsoniter.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 = jsoniter.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, errr := hex.DecodeString(serializedhex)
- if errr != nil {
- t.Errorf("bad test (arg 2 not hex %v) %d: %v", errr, 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 = jsoniter.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, errr := hex.DecodeString(serializedhex)
- if errr != nil {
- t.Errorf("bad test (arg 2 not hex %v) %d: %v", errr, 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 = jsoniter.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.ParseScript(subScript)
- if err != nil {
- t.Errorf("TestCalcSignatureHash failed test #%d: "+
- "Failed to parse sub-script: %v", i, err)
- continue
- }
- hashType := params.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)
- }
- }
- }
|