From d8306ee60205e682885234b4e360b1e59014765a Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Fri, 29 Jun 2018 11:58:31 -0500 Subject: [PATCH] txscript: Significantly improve errors. This converts the majority of script errors from generic errors created via errors.New and fmt.Errorf to use a concrete type that implements the error interface with an error code and description. This allows callers to programmatically detect the type of error via type assertions and an error code while still allowing the errors to provide more context. For example, instead of just having an error the reads "disabled opcode" as would happen prior to these changes when a disabled opcode is encountered, the error will now read "attempt to execute disabled opcode OP_FOO". While it was previously possible to programmatically detect many errors due to them being exported, they provided no additional context and there were also various instances that were just returning errors created on the spot which callers could not reliably detect without resorting to looking at the actual error message, which is nearly always bad practice. Also, while here, export the MaxStackSize and MaxScriptSize constants since they can be useful for consumers of the package and perform some minor cleanup of some of the tests. --- txscript/consensus.go | 6 +- txscript/data/script_valid.json | 2 - txscript/doc.go | 13 +- txscript/engine.go | 152 +++++--- txscript/engine_test.go | 21 +- txscript/error.go | 611 +++++++++++++++++++++++--------- txscript/error_test.go | 165 +++++++++ txscript/opcode.go | 226 ++++++++---- txscript/opcode_test.go | 11 +- txscript/reference_test.go | 22 +- txscript/script.go | 45 ++- txscript/script_test.go | 589 +++++++++++++++--------------- txscript/scriptbuilder.go | 20 +- txscript/scriptbuilder_test.go | 8 +- txscript/scriptnum.go | 21 +- txscript/scriptnum_test.go | 75 ++-- txscript/sighash.go | 5 +- txscript/stack.go | 33 +- txscript/stack_test.go | 106 ++++-- txscript/standard.go | 199 +++++++---- txscript/standard_test.go | 92 +++-- 21 files changed, 1575 insertions(+), 847 deletions(-) create mode 100644 txscript/error_test.go diff --git a/txscript/consensus.go b/txscript/consensus.go index 189b53bc..8a5e55f3 100644 --- a/txscript/consensus.go +++ b/txscript/consensus.go @@ -28,7 +28,7 @@ const ( func ExtractCoinbaseNullData(pkScript []byte) ([]byte, error) { pops, err := parseScript(pkScript) if err != nil { - return nil, fmt.Errorf("script parse failure") + return nil, err } // The nulldata in the coinbase must be a single OP_RETURN followed by a @@ -54,5 +54,7 @@ func ExtractCoinbaseNullData(pkScript []byte) ([]byte, error) { return pops[1].data, nil } - return nil, fmt.Errorf("not a properly-formed nulldata script") + str := fmt.Sprintf("script %x is not well-formed coinbase nulldata", + pkScript) + return nil, scriptError(ErrMalformedCoinbaseNullData, str) } diff --git a/txscript/data/script_valid.json b/txscript/data/script_valid.json index 621726b8..8157b0c2 100644 --- a/txscript/data/script_valid.json +++ b/txscript/data/script_valid.json @@ -48,8 +48,6 @@ ["'' 2147483647 2147483646", "SUBSTR '' EQUAL", "P2SH", "SUBSTR of an empty string produces an empty byte push regardless of out of bounds indices <=4 bytes"], ["'abcd' 3 3 1SUB", "SUBSTR 'c' EQUAL", "P2SH", "SUBSTR start index must work with the result of math operations"], ["'abcd' 4 1 SUB 2", "SUBSTR 'c' EQUAL", "P2SH", "SUBSTR end index must work with the result of math operations"], -["'abc' 2 0", "IF LEFT ELSE 1 ENDIF", "P2SH"], -["'abc' 2 0", "IF RIGHT ELSE 1 ENDIF", "P2SH"], ["Left substring related test coverage"], ["'abcd' 0", "LEFT NOT", "P2SH", "LEFT index of zero must produce empty byte push which is equivalent to FALSE"], diff --git a/txscript/doc.go b/txscript/doc.go index aae382cf..07d6387f 100644 --- a/txscript/doc.go +++ b/txscript/doc.go @@ -1,5 +1,5 @@ -// Copyright (c) 2013-2015 The btcsuite developers -// Copyright (c) 2015-2016 The Decred developers +// Copyright (c) 2013-2017 The btcsuite developers +// Copyright (c) 2015-2018 The Decred developers // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. @@ -29,8 +29,11 @@ what conditions must be met in order to spend decreds. Errors -Errors returned by this package are of the form txscript.ErrStackX where X -indicates the specific error. See Variables in the package documentation for a -full list. +Errors returned by this package are of type txscript.Error. This allows the +caller to programmatically determine the specific error by examining the +ErrorCode field of the type asserted txscript.Error while still providing rich +error messages with contextual information. A convenience function named +IsErrorCode is also provided to allow callers to easily check for a specific +error code. See ErrorCode in the package documentation for a full list. */ package txscript diff --git a/txscript/engine.go b/txscript/engine.go index ba04dbde..3cd542a8 100644 --- a/txscript/engine.go +++ b/txscript/engine.go @@ -1,5 +1,5 @@ -// Copyright (c) 2013-2016 The btcsuite developers -// Copyright (c) 2015-2017 The Decred developers +// Copyright (c) 2013-2017 The btcsuite developers +// Copyright (c) 2015-2018 The Decred developers // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. @@ -65,12 +65,12 @@ const ( ) const ( - // maxStackSize is the maximum combined height of stack and alt stack + // MaxStackSize is the maximum combined height of stack and alt stack // during execution. - maxStackSize = 1024 + MaxStackSize = 1024 - // maxScriptSize is the maximum allowed length of a raw script. - maxScriptSize = 16384 + // MaxScriptSize is the maximum allowed length of a raw script. + MaxScriptSize = 16384 // DefaultScriptVersion is the default scripting language version // representing extended Decred script. @@ -122,23 +122,31 @@ func (vm *Engine) isBranchExecuting() bool { func (vm *Engine) executeOpcode(pop *parsedOpcode) error { // Disabled opcodes are fail on program counter. if pop.isDisabled() { - return ErrStackOpDisabled + str := fmt.Sprintf("attempt to execute disabled opcode %s", + pop.opcode.name) + return scriptError(ErrDisabledOpcode, str) } // Always-illegal opcodes are fail on program counter. if pop.alwaysIllegal() { - return ErrStackReservedOpcode + str := fmt.Sprintf("attempt to execute reserved opcode %s", + pop.opcode.name) + return scriptError(ErrReservedOpcode, str) } // Note that this includes OP_RESERVED which counts as a push operation. if pop.opcode.value > OP_16 { vm.numOps++ if vm.numOps > MaxOpsPerScript { - return ErrStackTooManyOperations + str := fmt.Sprintf("exceeded max operation limit of %d", + MaxOpsPerScript) + return scriptError(ErrTooManyOperations, str) } } else if len(pop.data) > MaxScriptElementSize { - return ErrStackElementTooBig + str := fmt.Sprintf("element size %d exceeds max allowed size %d", + len(pop.data), MaxScriptElementSize) + return scriptError(ErrElementTooBig, str) } // Nothing left to do when this is not a conditional opcode and it is @@ -173,13 +181,15 @@ func (vm *Engine) disasm(scriptIdx int, scriptOff int) string { // execution, nil otherwise. func (vm *Engine) validPC() error { if vm.scriptIdx >= len(vm.scripts) { - return fmt.Errorf("past input scripts %v:%v %v:xxxx", + str := fmt.Sprintf("past input scripts %v:%v %v:xxxx", vm.scriptIdx, vm.scriptOff, len(vm.scripts)) + return scriptError(ErrInvalidProgramCounter, str) } if vm.scriptOff >= len(vm.scripts[vm.scriptIdx]) { - return fmt.Errorf("past input scripts %v:%v %v:%04d", + str := fmt.Sprintf("past input scripts %v:%v %v:%04d", vm.scriptIdx, vm.scriptOff, vm.scriptIdx, len(vm.scripts[vm.scriptIdx])) + return scriptError(ErrInvalidProgramCounter, str) } return nil } @@ -209,7 +219,9 @@ func (vm *Engine) DisasmPC() (string, error) { // script. func (vm *Engine) DisasmScript(idx int) (string, error) { if idx >= len(vm.scripts) { - return "", ErrStackInvalidIndex + str := fmt.Sprintf("script index %d >= total scripts %d", idx, + len(vm.scripts)) + return "", scriptError(ErrInvalidIndex, str) } var disstr string @@ -226,13 +238,18 @@ func (vm *Engine) CheckErrorCondition(finalScript bool) error { // Check execution is actually done. When pc is past the end of script // array there are no more scripts to run. if vm.scriptIdx < len(vm.scripts) { - return ErrStackScriptUnfinished + return scriptError(ErrScriptUnfinished, + "error check when script unfinished") } if finalScript && vm.hasFlag(ScriptVerifyCleanStack) && vm.dstack.Depth() != 1 { - return ErrStackCleanStack + + str := fmt.Sprintf("stack contains %d unexpected items", + vm.dstack.Depth()-1) + return scriptError(ErrCleanStack, str) } else if vm.dstack.Depth() < 1 { - return ErrStackEmptyStack + return scriptError(ErrEmptyStack, + "stack empty at end of script execution") } v, err := vm.dstack.PopBool() @@ -247,7 +264,8 @@ func (vm *Engine) CheckErrorCondition(finalScript bool) error { return fmt.Sprintf("scripts failed: script0: %s\n"+ "script1: %s", dis0, dis1) })) - return ErrStackScriptFailed + return scriptError(ErrEvalFalse, + "false stack entry at end of script execution") } return nil } @@ -276,8 +294,11 @@ func (vm *Engine) Step() (done bool, err error) { // The number of elements in the combination of the data and alt stacks // must not exceed the maximum number of stack elements allowed. - if vm.dstack.Depth()+vm.astack.Depth() > maxStackSize { - return false, ErrStackOverflow + combinedStackSize := vm.dstack.Depth() + vm.astack.Depth() + if combinedStackSize > MaxStackSize { + str := fmt.Sprintf("combined stack size %d > max allowed %d", + combinedStackSize, MaxStackSize) + return false, scriptError(ErrStackOverflow, str) } // Prepare for next instruction. @@ -285,7 +306,8 @@ func (vm *Engine) Step() (done bool, err error) { if vm.scriptOff >= len(vm.scripts[vm.scriptIdx]) { // Illegal to have an `if' that straddles two scripts. if err == nil && len(vm.condStack) != 0 { - return false, ErrStackMissingEndif + return false, scriptError(ErrUnbalancedConditional, + "end of script reached in conditional execution") } // Alt stack doesn't persist. @@ -384,7 +406,8 @@ func (vm *Engine) subScript() []parsedOpcode { func (vm *Engine) checkHashTypeEncoding(hashType SigHashType) error { sigHashType := hashType & ^SigHashAnyOneCanPay if sigHashType < SigHashAll || sigHashType > SigHashSingle { - return fmt.Errorf("invalid hashtype: 0x%x\n", hashType) + str := fmt.Sprintf("invalid hash type 0x%x", hashType) + return scriptError(ErrInvalidSigHashType, str) } return nil } @@ -400,7 +423,7 @@ func (vm *Engine) checkPubKeyEncoding(pubKey []byte) error { // Uncompressed return nil } - return ErrStackInvalidPubKey + return scriptError(ErrPubKeyType, "unsupported public key type") } // checkSignatureEncoding returns whether or not the passed signature adheres to @@ -469,25 +492,29 @@ func (vm *Engine) checkSignatureEncoding(sig []byte) error { // The signature must adhere to the minimum and maximum allowed length. sigLen := len(sig) if sigLen < minSigLen { - return fmt.Errorf("malformed signature: too short: %d < %d", sigLen, + str := fmt.Sprintf("malformed signature: too short: %d < %d", sigLen, minSigLen) + return scriptError(ErrSigTooShort, str) } if sigLen > maxSigLen { - return fmt.Errorf("malformed signature: too long: %d > %d", sigLen, + str := fmt.Sprintf("malformed signature: too long: %d > %d", sigLen, maxSigLen) + return scriptError(ErrSigTooLong, str) } // The signature must start with the ASN.1 sequence identifier. if sig[sequenceOffset] != asn1SequenceID { - return fmt.Errorf("malformed signature: format has wrong type: %#x", + str := fmt.Sprintf("malformed signature: format has wrong type: %#x", sig[sequenceOffset]) + return scriptError(ErrSigInvalidSeqID, str) } // The signature must indicate the correct amount of data for all elements // related to R and S. if int(sig[dataLenOffset]) != sigLen-2 { - return fmt.Errorf("malformed signature: bad length: %d != %d", + str := fmt.Sprintf("malformed signature: bad length: %d != %d", sig[dataLenOffset], sigLen-2) + return scriptError(ErrSigInvalidDataLen, str) } // Calculate the offsets of the elements related to S and ensure S is inside @@ -504,62 +531,76 @@ func (vm *Engine) checkSignatureEncoding(sig []byte) error { rLen := int(sig[rLenOffset]) sTypeOffset := rOffset + rLen sLenOffset := sTypeOffset + 1 - sOffset := sLenOffset + 1 - if sOffset > sigLen { - return fmt.Errorf("malformed signature: S out of bounds") + if sTypeOffset >= sigLen { + str := "malformed signature: S type indicator missing" + return scriptError(ErrSigMissingSTypeID, str) + } + if sLenOffset >= sigLen { + str := "malformed signature: S length missing" + return scriptError(ErrSigMissingSLen, str) } // The lengths of R and S must match the overall length of the signature. // // sLen specifies the length of the big-endian encoded number which // represents the S value of the signature. + sOffset := sLenOffset + 1 sLen := int(sig[sLenOffset]) if sOffset+sLen != sigLen { - return fmt.Errorf("malformed signature: invalid S length") + str := "malformed signature: invalid S length" + return scriptError(ErrSigInvalidSLen, str) } // R elements must be ASN.1 integers. if sig[rTypeOffset] != asn1IntegerID { - return fmt.Errorf("malformed signature: R integer marker: %#x != %#x", + str := fmt.Sprintf("malformed signature: R integer marker: %#x != %#x", sig[rTypeOffset], asn1IntegerID) + return scriptError(ErrSigInvalidRIntID, str) } // Zero-length integers are not allowed for R. if rLen == 0 { - return fmt.Errorf("malformed signature: R length is zero") + str := "malformed signature: R length is zero" + return scriptError(ErrSigZeroRLen, str) } // R must not be negative. if sig[rOffset]&0x80 != 0 { - return fmt.Errorf("malformed signature: R value is negative") + str := "malformed signature: R is negative" + return scriptError(ErrSigNegativeR, str) } // Null bytes at the start of R are not allowed, unless R would otherwise be // interpreted as a negative number. if rLen > 1 && sig[rOffset] == 0x00 && sig[rOffset+1]&0x80 == 0 { - return fmt.Errorf("malformed signature: invalid R value") + str := "malformed signature: R value has too much padding" + return scriptError(ErrSigTooMuchRPadding, str) } // S elements must be ASN.1 integers. if sig[sTypeOffset] != asn1IntegerID { - return fmt.Errorf("malformed signature: S integer marker: %#x != %#x", + str := fmt.Sprintf("malformed signature: S integer marker: %#x != %#x", sig[sTypeOffset], asn1IntegerID) + return scriptError(ErrSigInvalidSIntID, str) } // Zero-length integers are not allowed for S. if sLen == 0 { - return fmt.Errorf("malformed signature: S length is zero") + str := "malformed signature: S length is zero" + return scriptError(ErrSigZeroSLen, str) } // S must not be negative. if sig[sOffset]&0x80 != 0 { - return fmt.Errorf("malformed signature: S value is negative") + str := "malformed signature: S is negative" + return scriptError(ErrSigNegativeS, str) } // Null bytes at the start of S are not allowed, unless S would otherwise be // interpreted as a negative number. if sLen > 1 && sig[sOffset] == 0x00 && sig[sOffset+1]&0x80 == 0 { - return fmt.Errorf("malformed signature: invalid S value") + str := "malformed signature: S value has too much padding" + return scriptError(ErrSigTooMuchSPadding, str) } // Verify the S value is <= half the order of the curve. This check is done @@ -567,7 +608,8 @@ func (vm *Engine) checkSignatureEncoding(sig []byte) error { // instead which is a shorter encoding by 1 byte. sValue := new(big.Int).SetBytes(sig[sOffset : sOffset+sLen]) if sValue.Cmp(halfOrder) > 0 { - return ErrStackInvalidLowSSignature + return scriptError(ErrSigHighS, "signature is not canonical due to "+ + "unnecessarily high S value") } return nil @@ -621,15 +663,24 @@ func (vm *Engine) SetAltStack(data [][]byte) { // NewEngine returns a new script engine for the provided public key script, // transaction, and input index. The flags modify the behavior of the script // engine according to the description provided by each flag. -func NewEngine(scriptPubKey []byte, tx *wire.MsgTx, txIdx int, - flags ScriptFlags, scriptVersion uint16, sigCache *SigCache) (*Engine, error) { - +func NewEngine(scriptPubKey []byte, tx *wire.MsgTx, txIdx int, flags ScriptFlags, scriptVersion uint16, sigCache *SigCache) (*Engine, error) { // The provided transaction input index must refer to a valid input. if txIdx < 0 || txIdx >= len(tx.TxIn) { - return nil, ErrInvalidIndex + str := fmt.Sprintf("transaction input index %d is negative or "+ + ">= %d", txIdx, len(tx.TxIn)) + return nil, scriptError(ErrInvalidIndex, str) } scriptSig := tx.TxIn[txIdx].SignatureScript + // When both the signature script and public key script are empty the + // result is necessarily an error since the stack would end up being + // empty which is equivalent to a false top element. Thus, just return + // the relevant error now as an optimization. + if len(scriptSig) == 0 && len(scriptPubKey) == 0 { + return nil, scriptError(ErrEvalFalse, + "false stack entry at end of script execution") + } + // The clean stack flag (ScriptVerifyCleanStack) is not allowed without // the pay-to-script-hash (P2SH) evaluation (ScriptBip16) flag. // @@ -640,13 +691,15 @@ func NewEngine(scriptPubKey []byte, tx *wire.MsgTx, txIdx int, // it should be. vm := Engine{version: scriptVersion, flags: flags, sigCache: sigCache} if vm.hasFlag(ScriptVerifyCleanStack) && !vm.hasFlag(ScriptBip16) { - return nil, ErrInvalidFlags + return nil, scriptError(ErrInvalidFlags, + "invalid flags combination") } // The signature script must only contain data pushes when the // associated flag is set. if vm.hasFlag(ScriptVerifySigPushOnly) && !IsPushOnlyScript(scriptSig) { - return nil, ErrStackNonPushOnly + return nil, scriptError(ErrNotPushOnly, + "signature script is not push only") } // Subscripts for pay to script hash outputs are not allowed @@ -666,8 +719,10 @@ func NewEngine(scriptPubKey []byte, tx *wire.MsgTx, txIdx int, scripts := [][]byte{scriptSig, scriptPubKey} vm.scripts = make([][]parsedOpcode, len(scripts)) for i, scr := range scripts { - if len(scr) > maxScriptSize { - return nil, ErrStackLongScript + if len(scr) > MaxScriptSize { + str := fmt.Sprintf("script size %d is larger than max "+ + "allowed size %d", len(scr), MaxScriptSize) + return nil, scriptError(ErrScriptTooBig, str) } var err error vm.scripts[i], err = parseScript(scr) @@ -686,7 +741,8 @@ func NewEngine(scriptPubKey []byte, tx *wire.MsgTx, txIdx int, if vm.hasFlag(ScriptBip16) && isAnyKindOfScriptHash(vm.scripts[1]) { // Only accept input scripts that push data for P2SH. if !isPushOnly(vm.scripts[0]) { - return nil, ErrStackP2SHNonPushOnly + return nil, scriptError(ErrNotPushOnly, + "pay to script hash is not push only") } vm.bip16 = true } diff --git a/txscript/engine_test.go b/txscript/engine_test.go index 64454b5e..2cf2da2a 100644 --- a/txscript/engine_test.go +++ b/txscript/engine_test.go @@ -1,4 +1,4 @@ -// Copyright (c) 2013-2016 The btcsuite developers +// Copyright (c) 2013-2017 The btcsuite developers // Copyright (c) 2015-2018 The Decred developers // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. @@ -123,29 +123,24 @@ func TestCheckErrorCondition(t *testing.T) { for i := 0; i < len(pkScript)-1; i++ { done, err := vm.Step() if err != nil { - t.Errorf("failed to step %dth time: %v", i, err) - return + t.Fatalf("failed to step %dth time: %v", i, err) } if done { - t.Errorf("finshed early on %dth time", i) - return + t.Fatalf("finshed early on %dth time", i) } err = vm.CheckErrorCondition(false) - if err != ErrStackScriptUnfinished { - t.Errorf("got unexepected error %v on %dth iteration", + if !IsErrorCode(err, ErrScriptUnfinished) { + t.Fatalf("got unexepected error %v on %dth iteration", err, i) - return } } done, err := vm.Step() if err != nil { - t.Errorf("final step failed %v", err) - return + t.Fatalf("final step failed %v", err) } if !done { - t.Errorf("final step isn't done!") - return + t.Fatalf("final step isn't done!") } err = vm.CheckErrorCondition(false) @@ -194,7 +189,7 @@ func TestInvalidFlagCombinations(t *testing.T) { for i, test := range tests { _, err := NewEngine(pkScript, tx, 0, test, 0, nil) - if err != ErrInvalidFlags { + if !IsErrorCode(err, ErrInvalidFlags) { t.Fatalf("TestInvalidFlagCombinations #%d unexpected "+ "error: %v", i, err) } diff --git a/txscript/error.go b/txscript/error.go index dee12f3c..7eedbdc7 100644 --- a/txscript/error.go +++ b/txscript/error.go @@ -1,191 +1,476 @@ -// Copyright (c) 2013-2015 The btcsuite developers -// Copyright (c) 2015-2016 The Decred developers +// Copyright (c) 2013-2017 The btcsuite developers +// Copyright (c) 2015-2018 The Decred developers // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. package txscript import ( - "errors" "fmt" ) -// Engine execution errors. -var ( - // ErrStackShortScript is returned if the script has an opcode that is - // too long for the length of the script. - ErrStackShortScript = errors.New("execute past end of script") +// ErrorCode identifies a kind of script error. +type ErrorCode int - // ErrStackLongScript is returned if the script has an opcode that is - // too long for the length of the script. - ErrStackLongScript = errors.New("script is longer than maximum allowed") +// These constants are used to identify a specific Error. +const ( + // ErrInternal is returned if internal consistency checks fail. In + // practice this error should never be seen as it would mean there is an + // error in the engine logic. + ErrInternal ErrorCode = iota - // ErrStackUnderflow is returned if an opcode requires more items on the - // stack than is present.f - ErrStackUnderflow = errors.New("stack underflow") + // --------------------------------------- + // Failures related to improper API usage. + // --------------------------------------- - // ErrStackInvalidArgs is returned if the argument for an opcode is out - // of acceptable range. - ErrStackInvalidArgs = errors.New("invalid argument") - - // ErrStackOpDisabled is returned when a disabled opcode is encountered - // in the script. - ErrStackOpDisabled = errors.New("disabled opcode") - - // ErrStackVerifyFailed is returned when one of the OP_VERIFY or - // OP_*VERIFY instructions is executed and the conditions fails. - ErrStackVerifyFailed = errors.New("verify failed") - - // ErrStackNumberTooBig is returned when the argument for an opcode that - // should be an offset is obviously far too large. - ErrStackNumberTooBig = errors.New("number too big") - - // ErrStackInvalidOpcode is returned when an opcode marked as invalid or - // a completely undefined opcode is encountered. - ErrStackInvalidOpcode = errors.New("invalid opcode") - - // ErrStackReservedOpcode is returned when an opcode marked as reserved - // is encountered. - ErrStackReservedOpcode = errors.New("reserved opcode") - - // ErrStackEarlyReturn is returned when OP_RETURN is executed in the - // script. - ErrStackEarlyReturn = errors.New("script returned early") - - // ErrStackNoIf is returned if an OP_ELSE or OP_ENDIF is encountered - // without first having an OP_IF or OP_NOTIF in the script. - ErrStackNoIf = errors.New("OP_ELSE or OP_ENDIF with no matching OP_IF") - - // ErrStackMissingEndif is returned if the end of a script is reached - // without and OP_ENDIF to correspond to a conditional expression. - ErrStackMissingEndif = fmt.Errorf("execute fail, in conditional execution") - - // ErrStackTooManyPubKeys is returned if an OP_CHECKMULTISIG is - // encountered with more than MaxPubKeysPerMultiSig pubkeys present. - ErrStackTooManyPubKeys = errors.New("invalid pubkey count in OP_CHECKMULTISIG") - - // ErrStackTooManyOperations is returned if a script has more than - // MaxOpsPerScript opcodes that do not push data. - ErrStackTooManyOperations = errors.New("too many operations in script") - - // ErrStackElementTooBig is returned if the size of an element to be - // pushed to the stack is over MaxScriptElementSize. - ErrStackElementTooBig = errors.New("element in script too large") - - // ErrStackUnknownAddress is returned when ScriptToAddrHash does not - // recognize the pattern of the script and thus can not find the address - // for payment. - ErrStackUnknownAddress = errors.New("non-recognised address") - - // ErrStackScriptFailed is returned when at the end of a script the - // boolean on top of the stack is false signifying that the script has - // failed. - ErrStackScriptFailed = errors.New("execute fail, fail on stack") - - // ErrStackScriptUnfinished is returned when CheckErrorCondition is - // called on a script that has not finished executing. - ErrStackScriptUnfinished = errors.New("error check when script unfinished") - - // ErrStackEmptyStack is returned when the stack is empty at the end of - // execution. Normal operation requires that a boolean is on top of the - // stack when the scripts have finished executing. - ErrStackEmptyStack = errors.New("stack empty at end of execution") - - // ErrStackP2SHNonPushOnly is returned when a Pay-to-Script-Hash - // transaction is encountered and the ScriptSig does operations other - // than push data (in violation of bip16). - ErrStackP2SHNonPushOnly = errors.New("pay to script hash with non " + - "pushonly input") - - // ErrStackInvalidParseType is an internal error returned from - // ScriptToAddrHash ony if the internal data tables are wrong. - ErrStackInvalidParseType = errors.New("internal error: invalid parsetype found") - - // ErrStackInvalidAddrOffset is an internal error returned from - // ScriptToAddrHash ony if the internal data tables are wrong. - ErrStackInvalidAddrOffset = errors.New("internal error: invalid offset found") - - // ErrStackInvalidIndex is returned when an out-of-bounds index was - // passed to a function. - ErrStackInvalidIndex = errors.New("invalid script index") - - // ErrStackNonPushOnly is returned when ScriptInfo is called with a - // pkScript that peforms operations other that pushing data to the stack. - ErrStackNonPushOnly = errors.New("SigScript is non pushonly") - - // ErrStackOverflow is returned when stack and altstack combined depth - // is over the limit. - ErrStackOverflow = errors.New("stack overflow") - - // ErrStackInvalidLowSSignature is returned when the script contains any - // signatures whose S values are higher than the half order. - ErrStackInvalidLowSSignature = errors.New("invalid low s signature") - - // ErrStackInvalidPubKey is returned when the ScriptVerifyScriptEncoding - // flag is set and the script contains invalid pubkeys. - ErrStackInvalidPubKey = errors.New("invalid strict pubkey") - - // ErrStackCleanStack is returned when the ScriptVerifyCleanStack flag - // is set and after evalution the stack does not contain only one element, - // which also must be true if interpreted as a boolean. - ErrStackCleanStack = errors.New("stack is not clean") - - // ErrStackMinimalData is returned when the ScriptVerifyMinimalData flag - // is set and the script contains push operations that do not use - // the minimal opcode required. - ErrStackMinimalData = errors.New("non-minimally encoded script number") -) - -// Engine script errors. -var ( - // ErrInvalidFlags is returned when the passed flags to NewScript + // ErrInvalidFlags is returned when the passed flags to NewEngine // contain an invalid combination. - ErrInvalidFlags = errors.New("invalid flags combination") + ErrInvalidFlags - // ErrInvalidIndex is returned when the passed input index for the - // provided transaction is out of range. - ErrInvalidIndex = errors.New("invalid input index") + // ErrInvalidIndex is returned when an out-of-bounds index is passed to + // a function. + ErrInvalidIndex + + // ErrInvalidSigHashSingleIndex is returned when an attempt is + // made to sign an input with the SigHashSingle hash type and an + // index that is greater than or equal to the number of outputs. + ErrInvalidSigHashSingleIndex // ErrUnsupportedAddress is returned when a concrete type that // implements a dcrutil.Address is not a supported type. - ErrUnsupportedAddress = errors.New("unsupported address type") + ErrUnsupportedAddress - // ErrBadNumRequired is returned from MultiSigScript when nrequired is - // larger than the number of provided public keys. - ErrBadNumRequired = errors.New("more signatures required than keys present") + // ErrNotMultisigScript is returned from CalcMultiSigStats when the + // provided script is not a multisig script. + ErrNotMultisigScript - // ErrSighashSingleIdx - ErrSighashSingleIdx = errors.New("invalid SIGHASH_SINGLE script index") + // ErrTooManyRequiredSigs is returned from MultiSigScript when the + // specified number of required signatures is larger than the number of + // provided public keys. + ErrTooManyRequiredSigs - // ErrSubstrIndexNegative indicates that the substring index was negative - // and thus invalid. - ErrSubstrIdxNegative = errors.New("negative number given for substring " + - "index") + // ErrMalformedCoinbaseNullData is returned when the nulldata output + // of a coinbase transaction that is used to ensure the coinbase has a + // unique hash is not properly formed. + ErrMalformedCoinbaseNullData - // ErrSubstrIdxOutOfBounds indicates that the substring index was too large - // and thus invalid. - ErrSubstrIdxOutOfBounds = errors.New("out of bounds number given for " + - "substring index") + // ErrTooMuchNullData is returned from NullDataScript when the length of + // the provided data exceeds MaxDataCarrierSize. + ErrTooMuchNullData - // ErrNegativeRotation indicates that too low of a rotation depth was given - // for a uint32 bit rotation. - ErrNegativeRotation = errors.New("rotation depth negative") + // ------------------------------------------ + // Failures related to final execution state. + // ------------------------------------------ - // ErrRotationOverflow indicates that too high of a rotation depth was given - // for a uint32 bit rotation. - ErrRotationOverflow = errors.New("rotation depth out of bounds") + // ErrEarlyReturn is returned when OP_RETURN is executed in the script. + ErrEarlyReturn - // ErrNegativeRotation indicates that too low of a shift depth was given - // for a uint32 bit shift. - ErrNegativeShift = errors.New("shift depth negative") + // ErrEmptyStack is returned when the script evaluated without error, + // but terminated with an empty top stack element. + ErrEmptyStack - // ErrShiftOverflow indicates that too high of a shift depth was given - // for a uint32 bit shift. - ErrShiftOverflow = errors.New("shift depth out of bounds") + // ErrEvalFalse is returned when the script evaluated without error but + // terminated with a false top stack element. + ErrEvalFalse - // ErrDivideByZero indicates that a user attempted to divide by zero. - ErrDivideByZero = errors.New("division by zero") + // ErrScriptUnfinished is returned when CheckErrorCondition is called on + // a script that has not finished executing. + ErrScriptUnfinished - // ErrP2SHStakeOpCodes indicates a P2SH script contained stake op codes. - ErrP2SHStakeOpCodes = errors.New("stake opcodes were found in a p2sh script") + // ErrScriptDone is returned when an attempt to execute an opcode is + // made once all of them have already been executed. This can happen + // due to things such as a second call to Execute or calling Step after + // all opcodes have already been executed. + ErrInvalidProgramCounter + + // ----------------------------------------------------- + // Failures related to exceeding maximum allowed limits. + // ----------------------------------------------------- + + // ErrScriptTooBig is returned if a script is larger than MaxScriptSize. + ErrScriptTooBig + + // ErrElementTooBig is returned if the size of an element to be pushed + // to the stack is over MaxScriptElementSize. + ErrElementTooBig + + // ErrTooManyOperations is returned if a script has more than + // MaxOpsPerScript opcodes that do not push data. + ErrTooManyOperations + + // ErrStackOverflow is returned when stack and altstack combined depth + // is over the limit. + ErrStackOverflow + + // ErrInvalidPubKeyCount is returned when the number of public keys + // specified for a multsig is either negative or greater than + // MaxPubKeysPerMultiSig. + ErrInvalidPubKeyCount + + // ErrInvalidSignatureCount is returned when the number of signatures + // specified for a multisig is either negative or greater than the + // number of public keys. + ErrInvalidSignatureCount + + // ErrNumOutOfRange is returned when the argument for an opcode that + // expects numeric input is larger than the expected maximum number of + // bytes. For the most part, opcodes that deal with stack manipulation + // via offsets, arithmetic, numeric comparison, and boolean logic are + // those that this applies to. However, any opcode that expects numeric + // input may fail with this code. + ErrNumOutOfRange + + // -------------------------------------------- + // Failures related to verification operations. + // -------------------------------------------- + + // ErrVerify is returned when OP_VERIFY is encountered in a script and + // the top item on the data stack does not evaluate to true. + ErrVerify + + // ErrEqualVerify is returned when OP_EQUALVERIFY is encountered in a + // script and the top item on the data stack does not evaluate to true. + ErrEqualVerify + + // ErrNumEqualVerify is returned when OP_NUMEQUALVERIFY is encountered + // in a script and the top item on the data stack does not evaluate to + // true. + ErrNumEqualVerify + + // ErrCheckSigVerify is returned when OP_CHECKSIGVERIFY is encountered + // in a script and the top item on the data stack does not evaluate to + // true. + ErrCheckSigVerify + + // ErrCheckSigVerify is returned when OP_CHECKMULTISIGVERIFY is + // encountered in a script and the top item on the data stack does not + // evaluate to true. + ErrCheckMultiSigVerify + + // -------------------------------------------- + // Failures related to improper use of opcodes. + // -------------------------------------------- + + // ErrP2SHStakeOpCodes is returned when one or more stake opcodes are + // found in the redeem script of a pay-to-script-hash script. + ErrP2SHStakeOpCodes + + // ErrDisabledOpcode is returned when a disabled opcode is encountered + // in a script. + ErrDisabledOpcode + + // ErrReservedOpcode is returned when an opcode marked as reserved + // is encountered in a script. + ErrReservedOpcode + + // ErrMalformedPush is returned when a data push opcode tries to push + // more bytes than are left in the script. + ErrMalformedPush + + // ErrInvalidStackOperation is returned when a stack operation is + // attempted with a number that is invalid for the current stack size. + ErrInvalidStackOperation + + // ErrUnbalancedConditional is returned when an OP_ELSE or OP_ENDIF is + // encountered in a script without first having an OP_IF or OP_NOTIF or + // the end of script is reached without encountering an OP_ENDIF when + // an OP_IF or OP_NOTIF was previously encountered. + ErrUnbalancedConditional + + // ErrNegativeSubstrIdx is returned when an OP_SUBSTR, OP_LEFT, or + // OP_RIGHT opcode encounters a negative index. + ErrNegativeSubstrIdx + + // ErrOverflowSubstrIdx is returned when an OP_SUBSTR, OP_LEFT, or + // OP_RIGHT opcode encounters an index that is larger than the max + // allowed index that can operate on the string or the start index + // is greater than the end index for OP_SUBSTR. + ErrOverflowSubstrIdx + + // ErrNegativeRotation is returned when an OP_ROTL or OP_ROTR attempts + // to perform a rotation with a negative rotation count. + ErrNegativeRotation + + // ErrOverflowRotation is returned when an OP_ROTL or OP_ROTR opcode + // encounters a rotation count that is larger than the maximum allowed + // value for a uint32 bit rotation. + ErrOverflowRotation + + // ErrDivideByZero is returned when an OP_DIV of OP_MOD attempts to + // divide by zero. + ErrDivideByZero + + // ErrNegativeRotation is returned when an OP_LSHIFT or OP_RSHIFT opcode + // attempts to perform a shift with a negative count. + ErrNegativeShift + + // ErrOverflowShift is returned when an OP_LSHIFT or OP_RSHIFT opcode + // encounters a shift count that is larger than the maximum allowed value + // for a shift. + ErrOverflowShift + + // --------------------------------- + // Failures related to malleability. + // --------------------------------- + + // ErrMinimalData is returned when the ScriptVerifyMinimalData flag + // is set and the script contains push operations that do not use + // the minimal opcode required. + ErrMinimalData + + // ErrInvalidSigHashType is returned when a signature hash type is not + // one of the supported types. + ErrInvalidSigHashType + + // ErrSigTooShort is returned when the ScriptVerifyDERSignatures flag is + // set and a signature that should be a canonically-encoded DER + // signature is too short. + ErrSigTooShort + + // ErrSigTooLong is returned when the ScriptVerifyDERSignatures flag is + // set and a signature that should be a canonically-encoded DER + // signature is too long. + ErrSigTooLong + + // ErrSigInvalidSeqID is returned when the ScriptVerifyDERSignatures + // flag is set and a signature that should be a canonically-encoded DER + // signature does not have the expected ASN.1 sequence ID. + ErrSigInvalidSeqID + + // ErrSigInvalidDataLen is returned when the ScriptVerifyDERSignatures + // flag is set and a signature that should be a canonically-encoded DER + // signature does not specify the correct number of remaining bytes for + // the R and S portions. + ErrSigInvalidDataLen + + // ErrSigMissingSTypeID is returned when the ScriptVerifyDERSignatures + // flag is set and a signature that should be a canonically-encoded DER + // signature does not provide the ASN.1 type ID for S. + ErrSigMissingSTypeID + + // ErrSigMissingSLen is returned when the ScriptVerifyDERSignatures flag + // is set and a signature that should be a canonically-encoded DER + // signature does not provide the length of S. + ErrSigMissingSLen + + // ErrSigInvalidSLen is returned when the ScriptVerifyDERSignatures flag + // is set and a signature that should be a canonically-encoded DER + // signature does not specify the correct number of bytes for the S + // portion. + ErrSigInvalidSLen + + // ErrSigInvalidRIntID is returned when the ScriptVerifyDERSignatures + // flag is set and a signature that should be a canonically-encoded DER + // signature does not have the expected ASN.1 integer ID for R. + ErrSigInvalidRIntID + + // ErrSigZeroRLen is returned when the ScriptVerifyDERSignatures flag is + // set and a signature that should be a canonically-encoded DER + // signature has an R length of zero. + ErrSigZeroRLen + + // ErrSigNegativeR is returned when the ScriptVerifyDERSignatures flag + // is set and a signature that should be a canonically-encoded DER + // signature has a negative value for R. + ErrSigNegativeR + + // ErrSigTooMuchRPadding is returned when the ScriptVerifyDERSignatures flag + // is set and a signature that should be a canonically-encoded DER + // signature has too much padding for R. + ErrSigTooMuchRPadding + + // ErrSigInvalidSIntID is returned when the ScriptVerifyDERSignatures + // flag is set and a signature that should be a canonically-encoded DER + // signature does not have the expected ASN.1 integer ID for S. + ErrSigInvalidSIntID + + // ErrSigZeroSLen is returned when the ScriptVerifyDERSignatures flag is + // set and a signature that should be a canonically-encoded DER + // signature has an S length of zero. + ErrSigZeroSLen + + // ErrSigNegativeS is returned when the ScriptVerifyDERSignatures flag + // is set and a signature that should be a canonically-encoded DER + // signature has a negative value for S. + ErrSigNegativeS + + // ErrSigTooMuchSPadding is returned when the ScriptVerifyDERSignatures flag + // is set and a signature that should be a canonically-encoded DER + // signature has too much padding for S. + ErrSigTooMuchSPadding + + // ErrSigHighS is returned when the ScriptVerifyDERSignatures flag is + // set and a signature that should be a canonically-encoded DER signature + // has an S value that is higher than the curve half order. + ErrSigHighS + + // ErrNotPushOnly is returned when a script that is required to only + // push data to the stack performs other operations. A couple of cases + // where this applies is for a pay-to-script-hash signature script when + // bip16 is active and when the ScriptVerifySigPushOnly flag is set. + ErrNotPushOnly + + // ErrPubKeyType is returned when the ScriptVerifyStrictEncoding + // flag is set and the script contains invalid public keys. + ErrPubKeyType + + // ErrCleanStack is returned when the ScriptVerifyCleanStack flag + // is set, and after evalution, the stack does not contain only a + // single element. + ErrCleanStack + + // ------------------------------- + // Failures related to soft forks. + // ------------------------------- + + // ErrDiscourageUpgradableNOPs is returned when the + // ScriptDiscourageUpgradableNops flag is set and a NOP opcode is + // encountered in a script. + ErrDiscourageUpgradableNOPs + + // ErrNegativeLockTime is returned when a script contains an opcode that + // interprets a negative lock time. + ErrNegativeLockTime + + // ErrUnsatisfiedLockTime is returned when a script contains an opcode + // that involves a lock time and the required lock time has not been + // reached. + ErrUnsatisfiedLockTime + + // numErrorCodes is the maximum error code number used in tests. This + // entry MUST be the last entry in the enum. + numErrorCodes ) + +// Map of ErrorCode values back to their constant names for pretty printing. +var errorCodeStrings = map[ErrorCode]string{ + ErrInternal: "ErrInternal", + ErrInvalidFlags: "ErrInvalidFlags", + ErrInvalidIndex: "ErrInvalidIndex", + ErrInvalidSigHashSingleIndex: "ErrInvalidSigHashSingleIndex", + ErrUnsupportedAddress: "ErrUnsupportedAddress", + ErrNotMultisigScript: "ErrNotMultisigScript", + ErrTooManyRequiredSigs: "ErrTooManyRequiredSigs", + ErrMalformedCoinbaseNullData: "ErrMalformedCoinbaseNullData", + ErrTooMuchNullData: "ErrTooMuchNullData", + ErrEarlyReturn: "ErrEarlyReturn", + ErrEmptyStack: "ErrEmptyStack", + ErrEvalFalse: "ErrEvalFalse", + ErrScriptUnfinished: "ErrScriptUnfinished", + ErrInvalidProgramCounter: "ErrInvalidProgramCounter", + ErrScriptTooBig: "ErrScriptTooBig", + ErrElementTooBig: "ErrElementTooBig", + ErrTooManyOperations: "ErrTooManyOperations", + ErrStackOverflow: "ErrStackOverflow", + ErrInvalidPubKeyCount: "ErrInvalidPubKeyCount", + ErrInvalidSignatureCount: "ErrInvalidSignatureCount", + ErrNumOutOfRange: "ErrNumOutOfRange", + ErrVerify: "ErrVerify", + ErrEqualVerify: "ErrEqualVerify", + ErrNumEqualVerify: "ErrNumEqualVerify", + ErrCheckSigVerify: "ErrCheckSigVerify", + ErrCheckMultiSigVerify: "ErrCheckMultiSigVerify", + ErrP2SHStakeOpCodes: "ErrP2SHStakeOpCodes", + ErrDisabledOpcode: "ErrDisabledOpcode", + ErrReservedOpcode: "ErrReservedOpcode", + ErrMalformedPush: "ErrMalformedPush", + ErrInvalidStackOperation: "ErrInvalidStackOperation", + ErrUnbalancedConditional: "ErrUnbalancedConditional", + ErrNegativeSubstrIdx: "ErrNegativeSubstrIdx", + ErrSigTooMuchSPadding: "ErrSigTooMuchSPadding", + ErrOverflowSubstrIdx: "ErrOverflowSubstrIdx", + ErrNegativeRotation: "ErrNegativeRotation", + ErrOverflowRotation: "ErrOverflowRotation", + ErrDivideByZero: "ErrDivideByZero", + ErrNegativeShift: "ErrNegativeShift", + ErrOverflowShift: "ErrOverflowShift", + ErrMinimalData: "ErrMinimalData", + ErrInvalidSigHashType: "ErrInvalidSigHashType", + ErrSigTooShort: "ErrSigTooShort", + ErrSigTooLong: "ErrSigTooLong", + ErrSigInvalidSeqID: "ErrSigInvalidSeqID", + ErrSigInvalidDataLen: "ErrSigInvalidDataLen", + ErrSigMissingSTypeID: "ErrSigMissingSTypeID", + ErrSigMissingSLen: "ErrSigMissingSLen", + ErrSigInvalidSLen: "ErrSigInvalidSLen", + ErrSigInvalidRIntID: "ErrSigInvalidRIntID", + ErrSigZeroRLen: "ErrSigZeroRLen", + ErrSigNegativeR: "ErrSigNegativeR", + ErrSigTooMuchRPadding: "ErrSigTooMuchRPadding", + ErrSigInvalidSIntID: "ErrSigInvalidSIntID", + ErrSigZeroSLen: "ErrSigZeroSLen", + ErrSigNegativeS: "ErrSigNegativeS", + ErrSigHighS: "ErrSigHighS", + ErrNotPushOnly: "ErrNotPushOnly", + ErrPubKeyType: "ErrPubKeyType", + ErrCleanStack: "ErrCleanStack", + ErrDiscourageUpgradableNOPs: "ErrDiscourageUpgradableNOPs", + ErrNegativeLockTime: "ErrNegativeLockTime", + ErrUnsatisfiedLockTime: "ErrUnsatisfiedLockTime", +} + +// String returns the ErrorCode as a human-readable name. +func (e ErrorCode) String() string { + if s := errorCodeStrings[e]; s != "" { + return s + } + return fmt.Sprintf("Unknown ErrorCode (%d)", int(e)) +} + +// Error identifies a script-related error. It is used to indicate three +// classes of errors: +// 1) Script execution failures due to violating one of the many requirements +// imposed by the script engine or evaluating to false +// 2) Improper API usage by callers +// 3) Internal consistency check failures +// +// The caller can use type assertions on the returned errors to access the +// ErrorCode field to ascertain the specific reason for the error. As an +// additional convenience, the caller may make use of the IsErrorCode function +// to check for a specific error code. +type Error struct { + ErrorCode ErrorCode + Description string +} + +// Error satisfies the error interface and prints human-readable errors. +func (e Error) Error() string { + return e.Description +} + +// scriptError creates an Error given a set of arguments. +func scriptError(c ErrorCode, desc string) Error { + return Error{ErrorCode: c, Description: desc} +} + +// IsErrorCode returns whether or not the provided error is a script error with +// the provided error code. +func IsErrorCode(err error, c ErrorCode) bool { + serr, ok := err.(Error) + return ok && serr.ErrorCode == c +} + +// IsDERSigError returns whether or not the provided error is a script error +// with one of the error codes which are caused due to encountering a signature +// that is not a canonically-encoded DER signature. +// +// Note that the strict DER signature checks are only performed if scripts +// are executed with the ScriptVerifyDERSignatures flag. +func IsDERSigError(err error) bool { + serr, ok := err.(Error) + if !ok { + return false + } + + switch serr.ErrorCode { + case ErrSigTooShort, ErrSigTooLong, ErrSigInvalidSeqID, + ErrSigInvalidDataLen, ErrSigMissingSTypeID, ErrSigMissingSLen, + ErrSigInvalidSLen, ErrSigInvalidRIntID, ErrSigZeroRLen, ErrSigNegativeR, + ErrSigTooMuchRPadding, ErrSigInvalidSIntID, ErrSigZeroSLen, + ErrSigNegativeS, ErrSigTooMuchSPadding, ErrSigHighS: + + return true + } + + return false +} diff --git a/txscript/error_test.go b/txscript/error_test.go new file mode 100644 index 00000000..8bd7e39f --- /dev/null +++ b/txscript/error_test.go @@ -0,0 +1,165 @@ +// Copyright (c) 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 ( + "testing" +) + +// TestErrorCodeStringer tests the stringized output for the ErrorCode type. +func TestErrorCodeStringer(t *testing.T) { + t.Parallel() + + tests := []struct { + in ErrorCode + want string + }{ + {ErrInternal, "ErrInternal"}, + {ErrInvalidFlags, "ErrInvalidFlags"}, + {ErrInvalidIndex, "ErrInvalidIndex"}, + {ErrInvalidSigHashSingleIndex, "ErrInvalidSigHashSingleIndex"}, + {ErrUnsupportedAddress, "ErrUnsupportedAddress"}, + {ErrTooManyRequiredSigs, "ErrTooManyRequiredSigs"}, + {ErrMalformedCoinbaseNullData, "ErrMalformedCoinbaseNullData"}, + {ErrTooMuchNullData, "ErrTooMuchNullData"}, + {ErrNotMultisigScript, "ErrNotMultisigScript"}, + {ErrEarlyReturn, "ErrEarlyReturn"}, + {ErrEmptyStack, "ErrEmptyStack"}, + {ErrEvalFalse, "ErrEvalFalse"}, + {ErrScriptUnfinished, "ErrScriptUnfinished"}, + {ErrInvalidProgramCounter, "ErrInvalidProgramCounter"}, + {ErrScriptTooBig, "ErrScriptTooBig"}, + {ErrElementTooBig, "ErrElementTooBig"}, + {ErrTooManyOperations, "ErrTooManyOperations"}, + {ErrStackOverflow, "ErrStackOverflow"}, + {ErrInvalidPubKeyCount, "ErrInvalidPubKeyCount"}, + {ErrInvalidSignatureCount, "ErrInvalidSignatureCount"}, + {ErrNumOutOfRange, "ErrNumOutOfRange"}, + {ErrVerify, "ErrVerify"}, + {ErrEqualVerify, "ErrEqualVerify"}, + {ErrNumEqualVerify, "ErrNumEqualVerify"}, + {ErrCheckSigVerify, "ErrCheckSigVerify"}, + {ErrCheckMultiSigVerify, "ErrCheckMultiSigVerify"}, + {ErrP2SHStakeOpCodes, "ErrP2SHStakeOpCodes"}, + {ErrDisabledOpcode, "ErrDisabledOpcode"}, + {ErrReservedOpcode, "ErrReservedOpcode"}, + {ErrMalformedPush, "ErrMalformedPush"}, + {ErrInvalidStackOperation, "ErrInvalidStackOperation"}, + {ErrUnbalancedConditional, "ErrUnbalancedConditional"}, + {ErrNegativeSubstrIdx, "ErrNegativeSubstrIdx"}, + {ErrOverflowSubstrIdx, "ErrOverflowSubstrIdx"}, + {ErrNegativeRotation, "ErrNegativeRotation"}, + {ErrOverflowRotation, "ErrOverflowRotation"}, + {ErrDivideByZero, "ErrDivideByZero"}, + {ErrNegativeShift, "ErrNegativeShift"}, + {ErrOverflowShift, "ErrOverflowShift"}, + {ErrMinimalData, "ErrMinimalData"}, + {ErrInvalidSigHashType, "ErrInvalidSigHashType"}, + {ErrSigTooShort, "ErrSigTooShort"}, + {ErrSigTooLong, "ErrSigTooLong"}, + {ErrSigInvalidSeqID, "ErrSigInvalidSeqID"}, + {ErrSigInvalidDataLen, "ErrSigInvalidDataLen"}, + {ErrSigMissingSTypeID, "ErrSigMissingSTypeID"}, + {ErrSigMissingSLen, "ErrSigMissingSLen"}, + {ErrSigInvalidSLen, "ErrSigInvalidSLen"}, + {ErrSigInvalidRIntID, "ErrSigInvalidRIntID"}, + {ErrSigZeroRLen, "ErrSigZeroRLen"}, + {ErrSigNegativeR, "ErrSigNegativeR"}, + {ErrSigTooMuchRPadding, "ErrSigTooMuchRPadding"}, + {ErrSigInvalidSIntID, "ErrSigInvalidSIntID"}, + {ErrSigZeroSLen, "ErrSigZeroSLen"}, + {ErrSigNegativeS, "ErrSigNegativeS"}, + {ErrSigTooMuchSPadding, "ErrSigTooMuchSPadding"}, + {ErrSigHighS, "ErrSigHighS"}, + {ErrNotPushOnly, "ErrNotPushOnly"}, + {ErrPubKeyType, "ErrPubKeyType"}, + {ErrCleanStack, "ErrCleanStack"}, + {ErrDiscourageUpgradableNOPs, "ErrDiscourageUpgradableNOPs"}, + {ErrNegativeLockTime, "ErrNegativeLockTime"}, + {ErrUnsatisfiedLockTime, "ErrUnsatisfiedLockTime"}, + {0xffff, "Unknown ErrorCode (65535)"}, + } + + // Detect additional error codes that don't have the stringer added. + if len(tests)-1 != int(numErrorCodes) { + t.Errorf("It appears an error code was added without adding an " + + "associated stringer test") + } + + t.Logf("Running %d tests", len(tests)) + for i, test := range tests { + result := test.in.String() + if result != test.want { + t.Errorf("String #%d\n got: %s want: %s", i, result, + test.want) + continue + } + } +} + +// TestError tests the error output for the Error type. +func TestError(t *testing.T) { + t.Parallel() + + tests := []struct { + in Error + want string + }{ + { + Error{Description: "some error"}, + "some error", + }, + { + Error{Description: "human-readable error"}, + "human-readable error", + }, + } + + t.Logf("Running %d tests", len(tests)) + for i, test := range tests { + result := test.in.Error() + if result != test.want { + t.Errorf("Error #%d\n got: %s want: %s", i, result, + test.want) + continue + } + } +} + +// TestIsDERSigError ensures IsDERSigError returns true for all error codes +// that can be returned as a result of non-canonically-encoded DER signatures. +func TestIsDERSigError(t *testing.T) { + tests := []struct { + code ErrorCode + want bool + }{ + {ErrSigTooShort, true}, + {ErrSigTooLong, true}, + {ErrSigInvalidSeqID, true}, + {ErrSigInvalidDataLen, true}, + {ErrSigMissingSTypeID, true}, + {ErrSigMissingSLen, true}, + {ErrSigInvalidSLen, true}, + {ErrSigInvalidRIntID, true}, + {ErrSigZeroRLen, true}, + {ErrSigNegativeR, true}, + {ErrSigTooMuchRPadding, true}, + {ErrSigInvalidSIntID, true}, + {ErrSigZeroSLen, true}, + {ErrSigNegativeS, true}, + {ErrSigTooMuchSPadding, true}, + {ErrSigHighS, true}, + {ErrEvalFalse, false}, + {ErrInvalidIndex, false}, + } + for _, test := range tests { + result := IsDERSigError(Error{ErrorCode: test.code}) + if result != test.want { + t.Errorf("IsDERSigError(%v): unexpected result -- got: %v want: %v", + test.code, result, test.want) + continue + } + } +} diff --git a/txscript/opcode.go b/txscript/opcode.go index aa7c110e..29e4bac3 100644 --- a/txscript/opcode.go +++ b/txscript/opcode.go @@ -10,7 +10,6 @@ import ( "crypto/sha1" "crypto/sha256" "encoding/binary" - "errors" "fmt" "hash" @@ -683,28 +682,45 @@ func (pop *parsedOpcode) checkMinimalDataPush() error { opcode := pop.opcode.value if dataLen == 0 && opcode != OP_0 { - return ErrStackMinimalData + str := fmt.Sprintf("zero length data push is encoded with "+ + "opcode %s instead of OP_0", pop.opcode.name) + return scriptError(ErrMinimalData, str) } else if dataLen == 1 && data[0] >= 1 && data[0] <= 16 { if opcode != OP_1+data[0]-1 { // Should have used OP_1 .. OP_16 - return ErrStackMinimalData + str := fmt.Sprintf("data push of the value %d encoded "+ + "with opcode %s instead of OP_%d", data[0], + pop.opcode.name, data[0]) + return scriptError(ErrMinimalData, str) } } else if dataLen == 1 && data[0] == 0x81 { if opcode != OP_1NEGATE { - return ErrStackMinimalData + str := fmt.Sprintf("data push of the value -1 encoded "+ + "with opcode %s instead of OP_1NEGATE", + pop.opcode.name) + return scriptError(ErrMinimalData, str) } } else if dataLen <= 75 { if int(opcode) != dataLen { // Should have used a direct push - return ErrStackMinimalData + str := fmt.Sprintf("data push of %d bytes encoded "+ + "with opcode %s instead of OP_DATA_%d", dataLen, + pop.opcode.name, dataLen) + return scriptError(ErrMinimalData, str) } } else if dataLen <= 255 { if opcode != OP_PUSHDATA1 { - return ErrStackMinimalData + str := fmt.Sprintf("data push of %d bytes encoded "+ + "with opcode %s instead of OP_PUSHDATA1", + dataLen, pop.opcode.name) + return scriptError(ErrMinimalData, str) } } else if dataLen <= 65535 { if opcode != OP_PUSHDATA2 { - return ErrStackMinimalData + str := fmt.Sprintf("data push of %d bytes encoded "+ + "with opcode %s instead of OP_PUSHDATA2", + dataLen, pop.opcode.name) + return scriptError(ErrMinimalData, str) } } return nil @@ -765,7 +781,11 @@ func (pop *parsedOpcode) bytes() ([]byte, error) { retbytes[0] = pop.opcode.value if pop.opcode.length == 1 { if len(pop.data) != 0 { - return nil, ErrStackInvalidOpcode + str := fmt.Sprintf("internal consistency error - "+ + "parsed opcode %s has data length %d when %d "+ + "was expected", pop.opcode.name, len(pop.data), + 0) + return nil, scriptError(ErrInternal, str) } return retbytes, nil } @@ -794,7 +814,10 @@ func (pop *parsedOpcode) bytes() ([]byte, error) { retbytes = append(retbytes, pop.data...) if len(retbytes) != nbytes { - return nil, ErrStackInvalidOpcode + str := fmt.Sprintf("internal consistency error - "+ + "parsed opcode %s has data length %d when %d was "+ + "expected", pop.opcode.name, len(retbytes), nbytes) + return nil, scriptError(ErrInternal, str) } return retbytes, nil @@ -811,19 +834,25 @@ func (pop *parsedOpcode) bytes() ([]byte, error) { // dictate the script doesn't fail until the program counter passes over a // disabled opcode (even when they appear in a branch that is not executed). func opcodeDisabled(op *parsedOpcode, vm *Engine) error { - return ErrStackOpDisabled + str := fmt.Sprintf("attempt to execute disabled opcode %s", + op.opcode.name) + return scriptError(ErrDisabledOpcode, str) } // opcodeReserved is a common handler for all reserved opcodes. It returns an // appropriate error indicating the opcode is reserved. func opcodeReserved(op *parsedOpcode, vm *Engine) error { - return ErrStackReservedOpcode + str := fmt.Sprintf("attempt to execute reserved opcode %s", + op.opcode.name) + return scriptError(ErrReservedOpcode, str) } // opcodeInvalid is a common handler for all invalid opcodes. It returns an // appropriate error indicating the opcode is invalid. func opcodeInvalid(op *parsedOpcode, vm *Engine) error { - return ErrStackInvalidOpcode + str := fmt.Sprintf("attempt to execute invalid opcode %s", + op.opcode.name) + return scriptError(ErrReservedOpcode, str) } // opcodeFalse pushes an empty array to the data stack to represent false. Note @@ -881,8 +910,9 @@ func opcodeNop(op *parsedOpcode, vm *Engine) error { OP_UNKNOWN248: if vm.hasFlag(ScriptDiscourageUpgradableNops) { - return fmt.Errorf("%s reserved for upgrades", + str := fmt.Sprintf("%s reserved for upgrades", op.opcode.name) + return scriptError(ErrDiscourageUpgradableNOPs, str) } } return nil @@ -960,7 +990,9 @@ func opcodeNotIf(op *parsedOpcode, vm *Engine) error { // Conditional stack transformation: [... OpCondValue] -> [... !OpCondValue] func opcodeElse(op *parsedOpcode, vm *Engine) error { if len(vm.condStack) == 0 { - return ErrStackNoIf + str := fmt.Sprintf("encountered opcode %s with no matching "+ + "opcode to begin conditional execution", op.opcode.name) + return scriptError(ErrUnbalancedConditional, str) } conditionalIdx := len(vm.condStack) - 1 @@ -984,31 +1016,43 @@ func opcodeElse(op *parsedOpcode, vm *Engine) error { // Conditional stack transformation: [... OpCondValue] -> [...] func opcodeEndif(op *parsedOpcode, vm *Engine) error { if len(vm.condStack) == 0 { - return ErrStackNoIf + str := fmt.Sprintf("encountered opcode %s with no matching "+ + "opcode to begin conditional execution", op.opcode.name) + return scriptError(ErrUnbalancedConditional, str) } vm.condStack = vm.condStack[:len(vm.condStack)-1] return nil } -// opcodeVerify examines the top item on the data stack as a boolean value and -// verifies it evaluates to true. An error is returned if it does not. -func opcodeVerify(op *parsedOpcode, vm *Engine) error { +// abstractVerify examines the top item on the data stack as a boolean value and +// verifies it evaluates to true. An error is returned either when there is no +// item on the stack or when that item evaluates to false. In the latter case +// where the verification fails specifically due to the top item evaluating +// to false, the returned error will use the passed error code. +func abstractVerify(op *parsedOpcode, vm *Engine, c ErrorCode) error { verified, err := vm.dstack.PopBool() if err != nil { return err } if !verified { - return ErrStackVerifyFailed + str := fmt.Sprintf("%s failed", op.opcode.name) + return scriptError(c, str) } return nil } +// opcodeVerify examines the top item on the data stack as a boolean value and +// verifies it evaluates to true. An error is returned if it does not. +func opcodeVerify(op *parsedOpcode, vm *Engine) error { + return abstractVerify(op, vm, ErrVerify) +} + // opcodeReturn returns an appropriate error since it is always an error to // return early from a script. func opcodeReturn(op *parsedOpcode, vm *Engine) error { - return ErrStackEarlyReturn + return scriptError(ErrEarlyReturn, "script returned early") } // verifyLockTime is a helper function used to validate locktimes. @@ -1017,14 +1061,16 @@ func verifyLockTime(txLockTime, threshold, lockTime int64) error { // type. if !((txLockTime < threshold && lockTime < threshold) || (txLockTime >= threshold && lockTime >= threshold)) { - return fmt.Errorf("mismatched locktime types -- tx locktime %d, stack "+ - "locktime %d", txLockTime, lockTime) + str := fmt.Sprintf("mismatched locktime types -- tx locktime "+ + "%d, stack locktime %d", txLockTime, lockTime) + return scriptError(ErrUnsatisfiedLockTime, str) } if lockTime > txLockTime { - str := "locktime requirement not satisfied -- locktime is " + - "greater than the transaction locktime: %d > %d" - return fmt.Errorf(str, lockTime, txLockTime) + str := fmt.Sprintf("locktime requirement not satisfied -- "+ + "locktime is greater than the transaction locktime: "+ + "%d > %d", lockTime, txLockTime) + return scriptError(ErrUnsatisfiedLockTime, str) } return nil @@ -1040,8 +1086,8 @@ func opcodeCheckLockTimeVerify(op *parsedOpcode, vm *Engine) error { // opcode as OP_NOP2 instead. if !vm.hasFlag(ScriptVerifyCheckLockTimeVerify) { if vm.hasFlag(ScriptDiscourageUpgradableNops) { - return errors.New("OP_NOP2 reserved for soft-fork " + - "upgrades") + return scriptError(ErrDiscourageUpgradableNOPs, + "OP_NOP2 reserved for soft-fork upgrades") } return nil } @@ -1068,7 +1114,8 @@ func opcodeCheckLockTimeVerify(op *parsedOpcode, vm *Engine) error { // arithmetic being done first, you can always use // 0 OP_MAX OP_CHECKLOCKTIMEVERIFY. if lockTime < 0 { - return fmt.Errorf("negative locktime: %d", lockTime) + str := fmt.Sprintf("negative lock time: %d", lockTime) + return scriptError(ErrNegativeLockTime, str) } // The lock time field of a transaction is either a block height at @@ -1096,7 +1143,8 @@ func opcodeCheckLockTimeVerify(op *parsedOpcode, vm *Engine) error { // another input being unlocked, the opcode execution will still fail when the // input being used by the opcode is locked. if vm.tx.TxIn[vm.txIdx].Sequence == wire.MaxTxInSequenceNum { - return errors.New("transaction input is finalized") + return scriptError(ErrUnsatisfiedLockTime, + "transaction input is finalized") } return nil @@ -1112,8 +1160,8 @@ func opcodeCheckSequenceVerify(op *parsedOpcode, vm *Engine) error { // opcode as OP_NOP3 instead. if !vm.hasFlag(ScriptVerifyCheckSequenceVerify) { if vm.hasFlag(ScriptDiscourageUpgradableNops) { - return errors.New("OP_NOP3 reserved for soft-fork " + - "upgrades") + return scriptError(ErrDiscourageUpgradableNOPs, + "OP_NOP3 reserved for soft-fork upgrades") } return nil } @@ -1140,7 +1188,8 @@ func opcodeCheckSequenceVerify(op *parsedOpcode, vm *Engine) error { // arithmetic being done first, you can always use // 0 OP_MAX OP_CHECKSEQUENCEVERIFY. if stackSequence < 0 { - return fmt.Errorf("negative sequence: %d", stackSequence) + str := fmt.Sprintf("negative sequence: %d", stackSequence) + return scriptError(ErrNegativeLockTime, str) } sequence := int64(stackSequence) @@ -1155,8 +1204,9 @@ func opcodeCheckSequenceVerify(op *parsedOpcode, vm *Engine) error { // Transaction version numbers not high enough to trigger CSV rules must // fail. if vm.tx.Version < 2 { - return fmt.Errorf("invalid transaction version: %d", + str := fmt.Sprintf("invalid transaction version: %d", vm.tx.Version) + return scriptError(ErrUnsatisfiedLockTime, str) } // Sequence numbers with their most significant bit set are not @@ -1165,8 +1215,9 @@ func opcodeCheckSequenceVerify(op *parsedOpcode, vm *Engine) error { // to get around a CHECKSEQUENCEVERIFY check. txSequence := int64(vm.tx.TxIn[vm.txIdx].Sequence) if txSequence&int64(wire.SequenceLockTimeDisabled) != 0 { - return fmt.Errorf("transaction sequence has sequence "+ + str := fmt.Sprintf("transaction sequence has sequence "+ "locktime disabled bit set: 0x%x", txSequence) + return scriptError(ErrUnsatisfiedLockTime, str) } // Mask off non-consensus bits before doing comparisons. @@ -1393,7 +1444,9 @@ func opcodeCat(op *parsedOpcode, vm *Engine) error { // Ensure the result does not overflow the maximum stack item size. combinedLen := len(a) + len(b) if combinedLen > MaxScriptElementSize { - return ErrStackElementTooBig + str := fmt.Sprintf("element size %d exceeds max allowed size %d", + combinedLen, MaxScriptElementSize) + return scriptError(ErrElementTooBig, str) } // Push the concatenated result back to the stack. @@ -1446,17 +1499,28 @@ func opcodeSubstr(op *parsedOpcode, vm *Engine) error { // which means it is possible to provide a start index just after the // final character in the string, so long as the end index is the same // value, and an empty byte push will be produced. - if startIdx < 0 || endIdx < 0 { - return ErrSubstrIdxNegative + if startIdx < 0 { + str := fmt.Sprintf("start index %d is negative", startIdx) + return scriptError(ErrNegativeSubstrIdx, str) + } + if endIdx < 0 { + str := fmt.Sprintf("end index %d is negative", endIdx) + return scriptError(ErrNegativeSubstrIdx, str) } if startIdx > aLen { - return ErrSubstrIdxOutOfBounds + str := fmt.Sprintf("start index %d exceeds length %d", startIdx, + aLen) + return scriptError(ErrOverflowSubstrIdx, str) } if endIdx > aLen { - return ErrSubstrIdxOutOfBounds + str := fmt.Sprintf("end index %d exceeds length %d", endIdx, + aLen) + return scriptError(ErrOverflowSubstrIdx, str) } if startIdx > endIdx { - return ErrSubstrIdxOutOfBounds + str := fmt.Sprintf("start index %d is after end index %d", + startIdx, endIdx) + return scriptError(ErrOverflowSubstrIdx, str) } // Push the requested substring back to the stack. Note that identical @@ -1499,10 +1563,12 @@ func opcodeLeft(op *parsedOpcode, vm *Engine) error { // Ensure the provided index is in bounds. if endIdx < 0 { - return ErrSubstrIdxNegative + str := fmt.Sprintf("index %d is negative", endIdx) + return scriptError(ErrNegativeSubstrIdx, str) } if endIdx > aLen { - return ErrSubstrIdxOutOfBounds + str := fmt.Sprintf("index %d exceeds length %d", endIdx, aLen) + return scriptError(ErrOverflowSubstrIdx, str) } // Push the requested substring back to the stack. Note that a zero @@ -1542,7 +1608,6 @@ func opcodeRight(op *parsedOpcode, vm *Engine) error { vm.dstack.PushByteArray(nil) return nil } - // Ensure the provided index is in bounds. // // Take special note that the start index check is > as opposed to >=, @@ -1550,10 +1615,12 @@ func opcodeRight(op *parsedOpcode, vm *Engine) error { // final character in the string, and an empty byte push will be // produced. if startIdx < 0 { - return ErrSubstrIdxNegative + str := fmt.Sprintf("index %d is negative", startIdx) + return scriptError(ErrNegativeSubstrIdx, str) } if startIdx > aLen { - return ErrSubstrIdxOutOfBounds + str := fmt.Sprintf("index %d exceeds length %d", startIdx, aLen) + return scriptError(ErrOverflowSubstrIdx, str) } // Push the requested substring back to the stack. Note that a start @@ -1579,6 +1646,7 @@ func opcodeSize(op *parsedOpcode, vm *Engine) error { // opcodeInvert pops the top item off the stack, interprets it as an int32, // inverts the bits, and then pushes it back to the stack. +// // Stack transformation: [... x1] -> [... ~x1] func opcodeInvert(op *parsedOpcode, vm *Engine) error { v0, err := vm.dstack.PopInt(mathOpCodeMaxScriptNumLen) @@ -1592,6 +1660,7 @@ func opcodeInvert(op *parsedOpcode, vm *Engine) error { // opcodeAnd pops the top two items off the stack, interprets them as int32s, // bitwise ANDs the value, and then pushes the result back to the stack. +// // Stack transformation: [... x1 x2] -> [... x1 & x2] func opcodeAnd(op *parsedOpcode, vm *Engine) error { v0, err := vm.dstack.PopInt(mathOpCodeMaxScriptNumLen) @@ -1610,6 +1679,7 @@ func opcodeAnd(op *parsedOpcode, vm *Engine) error { // opcodeOr pops the top two items off the stack, interprets them as int32s, // bitwise ORs the value, and then pushes the result back to the stack. +// // Stack transformation: [... x1 x2] -> [... x1 | x2] func opcodeOr(op *parsedOpcode, vm *Engine) error { v0, err := vm.dstack.PopInt(mathOpCodeMaxScriptNumLen) @@ -1628,6 +1698,7 @@ func opcodeOr(op *parsedOpcode, vm *Engine) error { // opcodeXor pops the top two items off the stack, interprets them as int32s, // bitwise XORs the value, and then pushes the result back to the stack. +// // Stack transformation: [... x1 x2] -> [... x1 ^ x2] func opcodeXor(op *parsedOpcode, vm *Engine) error { v0, err := vm.dstack.PopInt(mathOpCodeMaxScriptNumLen) @@ -1672,7 +1743,7 @@ func opcodeEqual(op *parsedOpcode, vm *Engine) error { func opcodeEqualVerify(op *parsedOpcode, vm *Engine) error { err := opcodeEqual(op, vm) if err == nil { - err = opcodeVerify(op, vm) + err = abstractVerify(op, vm, ErrEqualVerify) } return err } @@ -1717,10 +1788,12 @@ func opcodeRotr(op *parsedOpcode, vm *Engine) error { // Don't allow invalid or pointless rotations. if count < 0 { - return ErrNegativeRotation + str := fmt.Sprintf("rotation count %d is negative", count) + return scriptError(ErrNegativeRotation, str) } if count > 31 { - return ErrRotationOverflow + str := fmt.Sprintf("rotation count %d > 31", count) + return scriptError(ErrOverflowRotation, str) } vm.dstack.PushInt(scriptNum(rotateRight(value, count))) @@ -1767,10 +1840,12 @@ func opcodeRotl(op *parsedOpcode, vm *Engine) error { // Don't allow invalid or pointless rotations. if count < 0 { - return ErrNegativeRotation + str := fmt.Sprintf("rotation count %d is negative", count) + return scriptError(ErrNegativeRotation, str) } if count > 31 { - return ErrRotationOverflow + str := fmt.Sprintf("rotation count %d > 31", count) + return scriptError(ErrOverflowRotation, str) } vm.dstack.PushInt(scriptNum(rotateLeft(value, count))) @@ -1963,7 +2038,7 @@ func opcodeDiv(op *parsedOpcode, vm *Engine) error { dividend := v1.Int32() if divisor == 0 { - return ErrDivideByZero + return scriptError(ErrDivideByZero, "division by zero") } vm.dstack.PushInt(scriptNum(dividend / divisor)) @@ -1994,7 +2069,7 @@ func opcodeMod(op *parsedOpcode, vm *Engine) error { dividend := v1.Int32() if divisor == 0 { - return ErrDivideByZero + return scriptError(ErrDivideByZero, "division by zero") } vm.dstack.PushInt(scriptNum(dividend % divisor)) @@ -2035,10 +2110,12 @@ func opcodeLShift(op *parsedOpcode, vm *Engine) error { // Don't allow invalid or pointless shifts. if count < 0 { - return ErrNegativeShift + str := fmt.Sprintf("shift count %d is negative", count) + return scriptError(ErrNegativeShift, str) } if count > 32 { - return ErrShiftOverflow + str := fmt.Sprintf("shift count %d > 32", count) + return scriptError(ErrOverflowShift, str) } vm.dstack.PushInt(scriptNum(value << uint(count))) @@ -2079,10 +2156,12 @@ func opcodeRShift(op *parsedOpcode, vm *Engine) error { // Don't allow invalid or pointless shifts. if count < 0 { - return ErrNegativeShift + str := fmt.Sprintf("shift count %d is negative", count) + return scriptError(ErrNegativeShift, str) } if count > 32 { - return ErrShiftOverflow + str := fmt.Sprintf("shift count %d > 32", count) + return scriptError(ErrOverflowShift, str) } vm.dstack.PushInt(scriptNum(value >> uint(count))) @@ -2179,7 +2258,7 @@ func opcodeNumEqual(op *parsedOpcode, vm *Engine) error { func opcodeNumEqualVerify(op *parsedOpcode, vm *Engine) error { err := opcodeNumEqual(op, vm) if err == nil { - err = opcodeVerify(op, vm) + err = abstractVerify(op, vm, ErrNumEqualVerify) } return err } @@ -2446,7 +2525,8 @@ func opcodeSha256(op *parsedOpcode, vm *Engine) error { // SHA256 opcode is not set. if !vm.hasFlag(ScriptVerifySHA256) { if vm.hasFlag(ScriptDiscourageUpgradableNops) { - return errors.New("OP_UNKNOWN192 reserved for upgrades") + return scriptError(ErrDiscourageUpgradableNOPs, + "OP_UNKNOWN192 reserved for upgrades") } return nil } @@ -2600,11 +2680,11 @@ func opcodeCheckSig(op *parsedOpcode, vm *Engine) error { // The opcodeCheckSig function is invoked followed by opcodeVerify. See the // documentation for each of those opcodes for more details. // -// Stack transformation: signature pubkey] -> [... bool] -> [...] +// Stack transformation: [... signature pubkey] -> [... bool] -> [...] func opcodeCheckSigVerify(op *parsedOpcode, vm *Engine) error { err := opcodeCheckSig(op, vm) if err == nil { - err = opcodeVerify(op, vm) + err = abstractVerify(op, vm, ErrCheckSigVerify) } return err } @@ -2638,12 +2718,21 @@ func opcodeCheckMultiSig(op *parsedOpcode, vm *Engine) error { } numPubKeys := int(numKeys.Int32()) - if numPubKeys < 0 || numPubKeys > MaxPubKeysPerMultiSig { - return ErrStackTooManyPubKeys + if numPubKeys < 0 { + str := fmt.Sprintf("number of pubkeys %d is negative", + numPubKeys) + return scriptError(ErrInvalidPubKeyCount, str) + } + if numPubKeys > MaxPubKeysPerMultiSig { + str := fmt.Sprintf("too many pubkeys: %d > %d", + numPubKeys, MaxPubKeysPerMultiSig) + return scriptError(ErrInvalidPubKeyCount, str) } vm.numOps += numPubKeys if vm.numOps > MaxOpsPerScript { - return ErrStackTooManyOperations + str := fmt.Sprintf("exceeded max operation limit of %d", + MaxOpsPerScript) + return scriptError(ErrTooManyOperations, str) } pubKeys := make([][]byte, 0, numPubKeys) @@ -2661,12 +2750,15 @@ func opcodeCheckMultiSig(op *parsedOpcode, vm *Engine) error { } numSignatures := int(numSigs.Int32()) if numSignatures < 0 { - return fmt.Errorf("number of signatures '%d' is less than 0", + str := fmt.Sprintf("number of signatures %d is negative", numSignatures) + return scriptError(ErrInvalidSignatureCount, str) + } if numSignatures > numPubKeys { - return fmt.Errorf("more signatures than pubkeys: %d > %d", + str := fmt.Sprintf("more signatures than pubkeys: %d > %d", numSignatures, numPubKeys) + return scriptError(ErrInvalidSignatureCount, str) } signatures := make([]*parsedSigInfo, 0, numSignatures) @@ -2802,11 +2894,11 @@ func opcodeCheckMultiSig(op *parsedOpcode, vm *Engine) error { // See the documentation for each of those opcodes for more details. // // Stack transformation: -// [... dummy [sig ...] numsigs [pubkey ...] numpubkeys] -> [... bool] -> [...] +// [... [sig ...] numsigs [pubkey ...] numpubkeys] -> [... bool] -> [...] func opcodeCheckMultiSigVerify(op *parsedOpcode, vm *Engine) error { err := opcodeCheckMultiSig(op, vm) if err == nil { - err = opcodeVerify(op, vm) + err = abstractVerify(op, vm, ErrCheckMultiSigVerify) } return err } diff --git a/txscript/opcode_test.go b/txscript/opcode_test.go index 0decc341..0223589e 100644 --- a/txscript/opcode_test.go +++ b/txscript/opcode_test.go @@ -1,5 +1,5 @@ -// Copyright (c) 2013-2016 The btcsuite developers -// Copyright (c) 2015-2017 The Decred developers +// Copyright (c) 2013-2017 The btcsuite developers +// Copyright (c) 2015-2018 The Decred developers // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. @@ -40,10 +40,11 @@ func TestOpcodeDisabled(t *testing.T) { } for _, opcodeVal := range tests { pop := parsedOpcode{opcode: &opcodeArray[opcodeVal], data: nil} - if err := opcodeDisabled(&pop, nil); err != ErrStackOpDisabled { + err := opcodeDisabled(&pop, nil) + if !IsErrorCode(err, ErrDisabledOpcode) { t.Errorf("opcodeDisabled: unexpected error - got %v, "+ - "want %v", err, ErrStackOpDisabled) - return + "want %v", err, ErrDisabledOpcode) + continue } } } diff --git a/txscript/reference_test.go b/txscript/reference_test.go index 8faabab6..656c284a 100644 --- a/txscript/reference_test.go +++ b/txscript/reference_test.go @@ -712,12 +712,13 @@ testloop: // parseSigHashExpectedResult parses the provided expected result string into // allowed error codes. An error is returned if the expected result string is // not supported. -func parseSigHashExpectedResult(expected string) (error, error) { +func parseSigHashExpectedResult(expected string) (*ErrorCode, error) { switch expected { case "OK": return nil, nil case "SIGHASH_SINGLE_IDX": - return ErrSighashSingleIdx, nil + code := ErrInvalidSigHashSingleIndex + return &code, nil } return nil, fmt.Errorf("unrecognized expected result in test data: %v", @@ -827,14 +828,21 @@ func TestCalcSignatureHashReference(t *testing.T) { // Calculate the signature hash and verify expected result. hash, err := calcSignatureHash(parsedScript, hashType, &tx, int(inputIdxF64), nil) - if err != expectedErr { - t.Errorf("Test #%d: unexpected error: want %v, got %v", i, - expectedErr, err) + if (err == nil) != (expectedErr == nil) || + expectedErr != nil && !IsErrorCode(err, *expectedErr) { + + if serr, ok := err.(Error); ok { + t.Errorf("Test #%d: want error code %v, got %v", i, expectedErr, + serr.ErrorCode) + continue + } + t.Errorf("Test #%d: want error code %v, got err: %v (%T)", i, + expectedErr, err, err) continue } if !bytes.Equal(hash, expectedHash) { - t.Errorf("Test #%d: signature hash mismatch - got %x, "+ - "want %x", i, hash, expectedHash) + t.Errorf("Test #%d: signature hash mismatch - got %x, want %x", i, + hash, expectedHash) continue } } diff --git a/txscript/script.go b/txscript/script.go index a900551f..a5c95139 100644 --- a/txscript/script.go +++ b/txscript/script.go @@ -1,4 +1,4 @@ -// Copyright (c) 2013-2016 The btcsuite developers +// Copyright (c) 2013-2017 The btcsuite developers // Copyright (c) 2015-2018 The Decred developers // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. @@ -98,8 +98,7 @@ func isAnyKindOfScriptHash(pops []parsedOpcode) bool { // HasP2SHScriptSigStakeOpCodes returns an error is the p2sh script has either // stake opcodes or if the pkscript cannot be retrieved. -func HasP2SHScriptSigStakeOpCodes(version uint16, scriptSig, - scriptPubKey []byte) error { +func HasP2SHScriptSigStakeOpCodes(version uint16, scriptSig, scriptPubKey []byte) error { class := GetScriptClass(version, scriptPubKey) if IsStakeOutput(scriptPubKey) { class, _ = GetStakeOutSubclass(scriptPubKey) @@ -110,11 +109,11 @@ func HasP2SHScriptSigStakeOpCodes(version uint16, scriptSig, // any stake tagging OP codes. pData, err := PushedData(scriptSig) if err != nil { - return fmt.Errorf("error retrieving pushed data "+ - "from script: %v", err) + return err } if len(pData) == 0 { - return fmt.Errorf("script has no pushed data") + str := "script has no pushed data" + return scriptError(ErrNotPushOnly, str) } // The pay-to-hash-script is the final data push of the @@ -123,11 +122,11 @@ func HasP2SHScriptSigStakeOpCodes(version uint16, scriptSig, hasStakeOpCodes, err := ContainsStakeOpCodes(shScript) if err != nil { - return fmt.Errorf("unexpected error checking pkscript "+ - "from p2sh transaction: %v", err.Error()) + return err } if hasStakeOpCodes { - return ErrP2SHStakeOpCodes + str := "stake opcodes were found in a p2sh script" + return scriptError(ErrP2SHStakeOpCodes, str) } } @@ -137,8 +136,7 @@ func HasP2SHScriptSigStakeOpCodes(version uint16, scriptSig, // parseScriptTemplate is the same as parseScript but allows the passing of the // template list for testing purposes. When there are parse errors, it returns // the list of parsed opcodes up to the point of failure along with the error. -func parseScriptTemplate(script []byte, opcodes *[256]opcode) ([]parsedOpcode, - error) { +func parseScriptTemplate(script []byte, opcodes *[256]opcode) ([]parsedOpcode, error) { retScript := make([]parsedOpcode, 0, len(script)) for i := 0; i < len(script); { instr := script[i] @@ -156,7 +154,11 @@ func parseScriptTemplate(script []byte, opcodes *[256]opcode) ([]parsedOpcode, // Data pushes of specific lengths -- OP_DATA_[1-75]. case op.length > 1: if len(script[i:]) < op.length { - return retScript, ErrStackShortScript + str := fmt.Sprintf("opcode %s requires %d "+ + "bytes, but script only has %d remaining", + op.name, op.length, len(script[i:])) + return retScript, scriptError(ErrMalformedPush, + str) } // Slice out the data. @@ -169,7 +171,11 @@ func parseScriptTemplate(script []byte, opcodes *[256]opcode) ([]parsedOpcode, off := i + 1 if len(script[off:]) < -op.length { - return retScript, ErrStackShortScript + str := fmt.Sprintf("opcode %s requires %d "+ + "bytes, but script only has %d remaining", + op.name, -op.length, len(script[off:])) + return retScript, scriptError(ErrMalformedPush, + str) } // Next -length bytes are little endian length of data. @@ -185,9 +191,10 @@ func parseScriptTemplate(script []byte, opcodes *[256]opcode) ([]parsedOpcode, (uint(script[off+1]) << 8) | uint(script[off])) default: - return retScript, - fmt.Errorf("invalid opcode length %d", - op.length) + str := fmt.Sprintf("invalid opcode length %d", + op.length) + return retScript, scriptError(ErrMalformedPush, + str) } // Move offset to beginning of the data. @@ -196,7 +203,11 @@ func parseScriptTemplate(script []byte, opcodes *[256]opcode) ([]parsedOpcode, // Disallow entries that do not fit script or were // sign extended. if int(l) > len(script[off:]) || int(l) < 0 { - return retScript, ErrStackShortScript + str := fmt.Sprintf("opcode %s pushes %d bytes, "+ + "but script only has %d remaining", + op.name, int(l), len(script[off:])) + return retScript, scriptError(ErrMalformedPush, + str) } pop.data = script[off : off+int(l)] diff --git a/txscript/script_test.go b/txscript/script_test.go index 0c1b88f5..8ec018ce 100644 --- a/txscript/script_test.go +++ b/txscript/script_test.go @@ -1,4 +1,4 @@ -// Copyright (c) 2013-2015 The btcsuite developers +// Copyright (c) 2013-2017 The btcsuite developers // Copyright (c) 2015-2018 The Decred developers // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. @@ -47,7 +47,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_FALSE], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_1 short", @@ -55,7 +55,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_1], data: nil, }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_1", @@ -71,7 +71,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_1], data: make([]byte, 2), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_2 short", @@ -79,7 +79,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_2], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_2", @@ -95,7 +95,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_2], data: make([]byte, 3), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_3 short", @@ -103,7 +103,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_3], data: make([]byte, 2), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_3", @@ -119,7 +119,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_3], data: make([]byte, 4), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_4 short", @@ -127,7 +127,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_4], data: make([]byte, 3), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_4", @@ -143,7 +143,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_4], data: make([]byte, 5), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_5 short", @@ -151,7 +151,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_5], data: make([]byte, 4), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_5", @@ -167,7 +167,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_5], data: make([]byte, 6), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_6 short", @@ -175,7 +175,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_6], data: make([]byte, 5), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_6", @@ -191,7 +191,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_6], data: make([]byte, 7), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_7 short", @@ -199,7 +199,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_7], data: make([]byte, 6), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_7", @@ -215,7 +215,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_7], data: make([]byte, 8), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_8 short", @@ -223,7 +223,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_8], data: make([]byte, 7), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_8", @@ -239,7 +239,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_8], data: make([]byte, 9), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_9 short", @@ -247,7 +247,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_9], data: make([]byte, 8), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_9", @@ -263,7 +263,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_9], data: make([]byte, 10), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_10 short", @@ -271,7 +271,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_10], data: make([]byte, 9), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_10", @@ -287,7 +287,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_10], data: make([]byte, 11), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_11 short", @@ -295,7 +295,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_11], data: make([]byte, 10), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_11", @@ -311,7 +311,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_11], data: make([]byte, 12), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_12 short", @@ -319,7 +319,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_12], data: make([]byte, 11), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_12", @@ -335,7 +335,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_12], data: make([]byte, 13), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_13 short", @@ -343,7 +343,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_13], data: make([]byte, 12), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_13", @@ -359,7 +359,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_13], data: make([]byte, 14), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_14 short", @@ -367,7 +367,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_14], data: make([]byte, 13), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_14", @@ -383,7 +383,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_14], data: make([]byte, 15), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_15 short", @@ -391,7 +391,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_15], data: make([]byte, 14), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_15", @@ -407,7 +407,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_15], data: make([]byte, 16), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_16 short", @@ -415,7 +415,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_16], data: make([]byte, 15), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_16", @@ -431,7 +431,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_16], data: make([]byte, 17), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_17 short", @@ -439,7 +439,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_17], data: make([]byte, 16), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_17", @@ -455,7 +455,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_17], data: make([]byte, 18), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_18 short", @@ -463,7 +463,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_18], data: make([]byte, 17), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_18", @@ -479,7 +479,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_18], data: make([]byte, 19), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_19 short", @@ -487,7 +487,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_19], data: make([]byte, 18), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_19", @@ -503,7 +503,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_19], data: make([]byte, 20), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_20 short", @@ -511,7 +511,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_20], data: make([]byte, 19), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_20", @@ -527,7 +527,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_20], data: make([]byte, 21), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_21 short", @@ -535,7 +535,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_21], data: make([]byte, 20), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_21", @@ -551,7 +551,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_21], data: make([]byte, 22), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_22 short", @@ -559,7 +559,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_22], data: make([]byte, 21), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_22", @@ -575,7 +575,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_22], data: make([]byte, 23), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_23 short", @@ -583,7 +583,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_23], data: make([]byte, 22), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_23", @@ -599,7 +599,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_23], data: make([]byte, 24), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_24 short", @@ -607,7 +607,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_24], data: make([]byte, 23), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_24", @@ -623,7 +623,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_24], data: make([]byte, 25), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_25 short", @@ -631,7 +631,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_25], data: make([]byte, 24), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_25", @@ -647,7 +647,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_25], data: make([]byte, 26), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_26 short", @@ -655,7 +655,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_26], data: make([]byte, 25), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_26", @@ -671,7 +671,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_26], data: make([]byte, 27), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_27 short", @@ -679,7 +679,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_27], data: make([]byte, 26), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_27", @@ -695,7 +695,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_27], data: make([]byte, 28), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_28 short", @@ -703,7 +703,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_28], data: make([]byte, 27), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_28", @@ -719,7 +719,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_28], data: make([]byte, 29), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_29 short", @@ -727,7 +727,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_29], data: make([]byte, 28), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_29", @@ -743,7 +743,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_29], data: make([]byte, 30), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_30 short", @@ -751,7 +751,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_30], data: make([]byte, 29), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_30", @@ -767,7 +767,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_30], data: make([]byte, 31), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_31 short", @@ -775,7 +775,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_31], data: make([]byte, 30), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_31", @@ -791,7 +791,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_31], data: make([]byte, 32), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_32 short", @@ -799,7 +799,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_32], data: make([]byte, 31), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_32", @@ -815,7 +815,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_32], data: make([]byte, 33), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_33 short", @@ -823,7 +823,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_33], data: make([]byte, 32), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_33", @@ -839,7 +839,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_33], data: make([]byte, 34), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_34 short", @@ -847,7 +847,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_34], data: make([]byte, 33), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_34", @@ -863,7 +863,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_34], data: make([]byte, 35), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_35 short", @@ -871,7 +871,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_35], data: make([]byte, 34), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_35", @@ -887,7 +887,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_35], data: make([]byte, 36), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_36 short", @@ -895,7 +895,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_36], data: make([]byte, 35), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_36", @@ -911,7 +911,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_36], data: make([]byte, 37), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_37 short", @@ -919,7 +919,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_37], data: make([]byte, 36), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_37", @@ -935,7 +935,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_37], data: make([]byte, 38), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_38 short", @@ -943,7 +943,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_38], data: make([]byte, 37), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_38", @@ -959,7 +959,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_38], data: make([]byte, 39), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_39 short", @@ -967,7 +967,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_39], data: make([]byte, 38), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_39", @@ -983,7 +983,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_39], data: make([]byte, 40), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_40 short", @@ -991,7 +991,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_40], data: make([]byte, 39), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_40", @@ -1007,7 +1007,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_40], data: make([]byte, 41), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_41 short", @@ -1015,7 +1015,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_41], data: make([]byte, 40), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_41", @@ -1031,7 +1031,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_41], data: make([]byte, 42), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_42 short", @@ -1039,7 +1039,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_42], data: make([]byte, 41), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_42", @@ -1055,7 +1055,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_42], data: make([]byte, 43), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_43 short", @@ -1063,7 +1063,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_43], data: make([]byte, 42), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_43", @@ -1079,7 +1079,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_43], data: make([]byte, 44), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_44 short", @@ -1087,7 +1087,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_44], data: make([]byte, 43), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_44", @@ -1103,7 +1103,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_44], data: make([]byte, 45), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_45 short", @@ -1111,7 +1111,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_45], data: make([]byte, 44), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_45", @@ -1127,7 +1127,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_45], data: make([]byte, 46), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_46 short", @@ -1135,7 +1135,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_46], data: make([]byte, 45), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_46", @@ -1151,7 +1151,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_46], data: make([]byte, 47), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_47 short", @@ -1159,7 +1159,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_47], data: make([]byte, 46), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_47", @@ -1175,7 +1175,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_47], data: make([]byte, 48), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_48 short", @@ -1183,7 +1183,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_48], data: make([]byte, 47), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_48", @@ -1199,7 +1199,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_48], data: make([]byte, 49), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_49 short", @@ -1207,7 +1207,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_49], data: make([]byte, 48), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_49", @@ -1223,7 +1223,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_49], data: make([]byte, 50), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_50 short", @@ -1231,7 +1231,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_50], data: make([]byte, 49), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_50", @@ -1247,7 +1247,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_50], data: make([]byte, 51), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_51 short", @@ -1255,7 +1255,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_51], data: make([]byte, 50), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_51", @@ -1271,7 +1271,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_51], data: make([]byte, 52), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_52 short", @@ -1279,7 +1279,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_52], data: make([]byte, 51), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_52", @@ -1295,7 +1295,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_52], data: make([]byte, 53), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_53 short", @@ -1303,7 +1303,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_53], data: make([]byte, 52), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_53", @@ -1319,7 +1319,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_53], data: make([]byte, 54), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_54 short", @@ -1327,7 +1327,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_54], data: make([]byte, 53), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_54", @@ -1343,7 +1343,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_54], data: make([]byte, 55), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_55 short", @@ -1351,7 +1351,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_55], data: make([]byte, 54), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_55", @@ -1367,7 +1367,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_55], data: make([]byte, 56), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_56 short", @@ -1375,7 +1375,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_56], data: make([]byte, 55), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_56", @@ -1391,7 +1391,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_56], data: make([]byte, 57), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_57 short", @@ -1399,7 +1399,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_57], data: make([]byte, 56), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_57", @@ -1415,7 +1415,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_57], data: make([]byte, 58), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_58 short", @@ -1423,7 +1423,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_58], data: make([]byte, 57), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_58", @@ -1439,7 +1439,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_58], data: make([]byte, 59), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_59 short", @@ -1447,7 +1447,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_59], data: make([]byte, 58), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_59", @@ -1463,7 +1463,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_59], data: make([]byte, 60), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_60 short", @@ -1471,7 +1471,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_60], data: make([]byte, 59), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_60", @@ -1487,7 +1487,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_60], data: make([]byte, 61), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_61 short", @@ -1495,7 +1495,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_61], data: make([]byte, 60), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_61", @@ -1511,7 +1511,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_61], data: make([]byte, 62), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_62 short", @@ -1519,7 +1519,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_62], data: make([]byte, 61), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_62", @@ -1535,7 +1535,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_62], data: make([]byte, 63), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_63 short", @@ -1543,7 +1543,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_63], data: make([]byte, 62), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_63", @@ -1559,7 +1559,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_63], data: make([]byte, 64), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_64 short", @@ -1567,7 +1567,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_64], data: make([]byte, 63), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_64", @@ -1583,7 +1583,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_64], data: make([]byte, 65), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_65 short", @@ -1591,7 +1591,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_65], data: make([]byte, 64), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_65", @@ -1607,7 +1607,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_65], data: make([]byte, 66), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_66 short", @@ -1615,7 +1615,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_66], data: make([]byte, 65), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_66", @@ -1631,7 +1631,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_66], data: make([]byte, 67), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_67 short", @@ -1639,7 +1639,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_67], data: make([]byte, 66), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_67", @@ -1655,7 +1655,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_67], data: make([]byte, 68), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_68 short", @@ -1663,7 +1663,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_68], data: make([]byte, 67), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_68", @@ -1679,7 +1679,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_68], data: make([]byte, 69), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_69 short", @@ -1687,7 +1687,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_69], data: make([]byte, 68), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_69", @@ -1703,7 +1703,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_69], data: make([]byte, 70), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_70 short", @@ -1711,7 +1711,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_70], data: make([]byte, 69), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_70", @@ -1727,7 +1727,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_70], data: make([]byte, 71), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_71 short", @@ -1735,7 +1735,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_71], data: make([]byte, 70), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_71", @@ -1751,7 +1751,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_71], data: make([]byte, 72), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_72 short", @@ -1759,7 +1759,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_72], data: make([]byte, 71), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_72", @@ -1775,7 +1775,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_72], data: make([]byte, 73), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_73 short", @@ -1783,7 +1783,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_73], data: make([]byte, 72), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_73", @@ -1799,7 +1799,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_73], data: make([]byte, 74), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_74 short", @@ -1807,7 +1807,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_74], data: make([]byte, 73), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_74", @@ -1823,7 +1823,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_74], data: make([]byte, 75), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_75 short", @@ -1831,7 +1831,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_75], data: make([]byte, 74), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_75", @@ -1847,7 +1847,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_75], data: make([]byte, 76), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_PUSHDATA1", @@ -1887,7 +1887,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_1NEGATE], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_RESERVED", @@ -1903,7 +1903,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_RESERVED], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_TRUE", @@ -1919,7 +1919,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_TRUE], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_2", @@ -1935,7 +1935,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_2], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_2", @@ -1951,7 +1951,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_2], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_3", @@ -1967,7 +1967,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_3], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_4", @@ -1983,7 +1983,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_4], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_5", @@ -1999,7 +1999,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_5], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_6", @@ -2015,7 +2015,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_6], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_7", @@ -2031,7 +2031,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_7], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_8", @@ -2047,7 +2047,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_8], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_9", @@ -2063,7 +2063,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_9], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_10", @@ -2079,7 +2079,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_10], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_11", @@ -2095,7 +2095,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_11], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_12", @@ -2111,7 +2111,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_12], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_13", @@ -2127,7 +2127,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_13], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_14", @@ -2143,7 +2143,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_14], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_15", @@ -2159,7 +2159,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_15], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_16", @@ -2175,7 +2175,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_16], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_NOP", @@ -2191,7 +2191,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_NOP], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_VER", @@ -2207,7 +2207,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_VER], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_IF", @@ -2223,7 +2223,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_IF], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_NOTIF", @@ -2239,7 +2239,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_NOTIF], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_VERIF", @@ -2255,7 +2255,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_VERIF], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_VERNOTIF", @@ -2271,7 +2271,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_VERNOTIF], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_ELSE", @@ -2287,7 +2287,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_ELSE], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_ENDIF", @@ -2303,7 +2303,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_ENDIF], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_VERIFY", @@ -2319,7 +2319,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_VERIFY], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_RETURN", @@ -2335,7 +2335,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_RETURN], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_TOALTSTACK", @@ -2351,7 +2351,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_TOALTSTACK], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_FROMALTSTACK", @@ -2367,7 +2367,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_FROMALTSTACK], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_2DROP", @@ -2383,7 +2383,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_2DROP], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_2DUP", @@ -2399,7 +2399,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_2DUP], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_3DUP", @@ -2415,7 +2415,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_3DUP], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_2OVER", @@ -2431,7 +2431,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_2OVER], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_2ROT", @@ -2447,7 +2447,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_2ROT], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_2SWAP", @@ -2463,7 +2463,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_2SWAP], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_IFDUP", @@ -2479,7 +2479,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_IFDUP], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DEPTH", @@ -2495,7 +2495,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DEPTH], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DROP", @@ -2511,7 +2511,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DROP], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DUP", @@ -2527,7 +2527,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DUP], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_NIP", @@ -2543,7 +2543,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_NIP], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_OVER", @@ -2559,7 +2559,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_OVER], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_PICK", @@ -2575,7 +2575,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_PICK], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_ROLL", @@ -2591,7 +2591,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_ROLL], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_ROT", @@ -2607,7 +2607,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_ROT], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_SWAP", @@ -2623,7 +2623,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_SWAP], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_TUCK", @@ -2639,7 +2639,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_TUCK], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_CAT", @@ -2655,7 +2655,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_CAT], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_SUBSTR", @@ -2671,7 +2671,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_SUBSTR], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_LEFT", @@ -2687,7 +2687,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_LEFT], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_LEFT", @@ -2703,7 +2703,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_LEFT], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_RIGHT", @@ -2719,7 +2719,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_RIGHT], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_SIZE", @@ -2735,7 +2735,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_SIZE], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_INVERT", @@ -2751,7 +2751,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_INVERT], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_AND", @@ -2767,7 +2767,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_AND], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_OR", @@ -2783,7 +2783,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_OR], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_XOR", @@ -2799,7 +2799,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_XOR], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_EQUAL", @@ -2815,7 +2815,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_EQUAL], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_EQUALVERIFY", @@ -2831,7 +2831,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_EQUALVERIFY], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_ROTR", @@ -2847,7 +2847,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_ROTR], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_ROTL", @@ -2863,7 +2863,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_ROTL], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_1ADD", @@ -2879,7 +2879,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_1ADD], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_1SUB", @@ -2895,7 +2895,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_1SUB], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_2MUL", @@ -2911,7 +2911,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_2MUL], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_2DIV", @@ -2927,7 +2927,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_2DIV], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_NEGATE", @@ -2943,7 +2943,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_NEGATE], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_ABS", @@ -2959,7 +2959,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_ABS], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_NOT", @@ -2975,7 +2975,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_NOT], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_0NOTEQUAL", @@ -2991,7 +2991,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_0NOTEQUAL], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_ADD", @@ -3007,7 +3007,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_ADD], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_SUB", @@ -3023,7 +3023,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_SUB], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_MUL", @@ -3039,7 +3039,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_MUL], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DIV", @@ -3055,7 +3055,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DIV], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_MOD", @@ -3071,7 +3071,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_MOD], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_LSHIFT", @@ -3087,7 +3087,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_LSHIFT], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_RSHIFT", @@ -3103,7 +3103,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_RSHIFT], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_BOOLAND", @@ -3119,7 +3119,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_BOOLAND], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_BOOLOR", @@ -3135,7 +3135,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_BOOLOR], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_NUMEQUAL", @@ -3151,7 +3151,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_NUMEQUAL], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_NUMEQUALVERIFY", @@ -3167,7 +3167,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_NUMEQUALVERIFY], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_NUMNOTEQUAL", @@ -3183,7 +3183,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_NUMNOTEQUAL], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_LESSTHAN", @@ -3199,7 +3199,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_LESSTHAN], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_GREATERTHAN", @@ -3215,7 +3215,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_GREATERTHAN], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_LESSTHANOREQUAL", @@ -3231,7 +3231,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_LESSTHANOREQUAL], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_GREATERTHANOREQUAL", @@ -3247,7 +3247,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_GREATERTHANOREQUAL], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_MIN", @@ -3263,7 +3263,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_MIN], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_MAX", @@ -3279,7 +3279,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_MAX], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_WITHIN", @@ -3295,7 +3295,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_WITHIN], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_RIPEMD160", @@ -3311,7 +3311,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_RIPEMD160], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_SHA1", @@ -3327,7 +3327,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_SHA1], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_SHA256", @@ -3337,6 +3337,14 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { }, expectedErr: nil, }, + { + name: "OP_SHA256 long", + pop: &parsedOpcode{ + opcode: &opcodeArray[OP_SHA256], + data: make([]byte, 1), + }, + expectedErr: scriptError(ErrInternal, ""), + }, { name: "OP_BLAKE256", pop: &parsedOpcode{ @@ -3351,7 +3359,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_BLAKE256], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_HASH160", @@ -3367,7 +3375,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_HASH160], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_HASH256", @@ -3383,7 +3391,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_HASH256], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_CODESAPERATOR", @@ -3399,7 +3407,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_CODESEPARATOR], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_CHECKSIG", @@ -3415,7 +3423,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_CHECKSIG], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_CHECKSIGVERIFY", @@ -3431,7 +3439,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_CHECKSIGVERIFY], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_CHECKMULTISIG", @@ -3447,7 +3455,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_CHECKMULTISIG], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_CHECKMULTISIGVERIFY", @@ -3463,7 +3471,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_CHECKMULTISIGVERIFY], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_NOP1", @@ -3479,7 +3487,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_NOP1], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_NOP2", @@ -3495,7 +3503,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_NOP2], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_NOP3", @@ -3511,7 +3519,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_NOP3], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_NOP4", @@ -3527,7 +3535,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_NOP4], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_NOP5", @@ -3543,7 +3551,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_NOP5], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_NOP6", @@ -3559,7 +3567,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_NOP6], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_NOP7", @@ -3575,7 +3583,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_NOP7], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_NOP8", @@ -3591,7 +3599,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_NOP8], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_NOP9", @@ -3607,7 +3615,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_NOP9], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_NOP10", @@ -3623,7 +3631,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_NOP10], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_PUBKEYHASH", @@ -3639,7 +3647,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_PUBKEYHASH], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_PUBKEY", @@ -3655,7 +3663,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_PUBKEY], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_INVALIDOPCODE", @@ -3671,15 +3679,15 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_INVALIDOPCODE], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, } for _, test := range tests { _, err := test.pop.bytes() - if err != test.expectedErr { - t.Errorf("Parsed Opcode test '%s' failed", test.name) - t.Error(err, test.expectedErr) + if e := tstCheckScriptError(err, test.expectedErr); e != nil { + t.Errorf("Parsed opcode test '%s': %v", test.name, e) + continue } } } @@ -3811,12 +3819,10 @@ func TestGetPreciseSigOps(t *testing.T) { name string scriptSig []byte nSigOps int - err error }{ { name: "scriptSig doesn't parse", scriptSig: mustParseShortForm("PUSHDATA1 0x02"), - err: ErrStackShortScript, }, { name: "scriptSig isn't push only", @@ -3837,7 +3843,6 @@ func TestGetPreciseSigOps(t *testing.T) { { name: "pushed script doesn't parse", scriptSig: mustParseShortForm("DATA_2 PUSHDATA1 0x02"), - err: ErrStackShortScript, }, } @@ -3900,13 +3905,13 @@ func TestRemoveOpcodes(t *testing.T) { name: "invalid length (insruction)", before: "PUSHDATA1", remove: OP_CODESEPARATOR, - err: ErrStackShortScript, + err: scriptError(ErrMalformedPush, ""), }, { name: "invalid length (data)", before: "PUSHDATA1 0xff 0xfe", remove: OP_CODESEPARATOR, - err: ErrStackShortScript, + err: scriptError(ErrMalformedPush, ""), }, } @@ -3926,20 +3931,14 @@ func TestRemoveOpcodes(t *testing.T) { before := mustParseShortForm(test.before) after := mustParseShortForm(test.after) result, err := tstRemoveOpcode(before, test.remove) - if test.err != nil { - if err != test.err { - t.Errorf("%s: got unexpected error. exp: \"%v\" "+ - "got: \"%v\"", test.name, test.err, err) - } - return - } - if err != nil { - t.Errorf("%s: unexpected failure: \"%v\"", test.name, err) - return + if e := tstCheckScriptError(err, test.err); e != nil { + t.Errorf("%s: %v", test.name, e) + continue } + if !bytes.Equal(after, result) { - t.Errorf("%s: value does not equal expected: exp: \"%v\""+ - " got: \"%v\"", test.name, after, result) + t.Errorf("%s: value does not equal expected: exp: %q"+ + " got: %q", test.name, after, result) } } } @@ -4075,13 +4074,13 @@ func TestRemoveOpcodeByData(t *testing.T) { name: "invalid length (instruction)", before: []byte{OP_PUSHDATA1}, remove: []byte{1, 2, 3, 4}, - err: ErrStackShortScript, + err: scriptError(ErrMalformedPush, ""), }, { name: "invalid length (data)", before: []byte{OP_PUSHDATA1, 255, 254}, remove: []byte{1, 2, 3, 4}, - err: ErrStackShortScript, + err: scriptError(ErrMalformedPush, ""), }, } @@ -4099,20 +4098,14 @@ func TestRemoveOpcodeByData(t *testing.T) { for _, test := range tests { result, err := tstRemoveOpcodeByData(test.before, test.remove) - if test.err != nil { - if err != test.err { - t.Errorf("%s: got unexpected error. exp: \"%v\" "+ - "got: \"%v\"", test.name, test.err, err) - } - return - } - if err != nil { - t.Errorf("%s: unexpected failure: \"%v\"", test.name, err) - return + if e := tstCheckScriptError(err, test.err); e != nil { + t.Errorf("%s: %v", test.name, e) + continue } + if !bytes.Equal(test.after, result) { - t.Errorf("%s: value does not equal expected: exp: \"%v\""+ - " got: \"%v\"", test.name, test.after, result) + t.Errorf("%s: value does not equal expected: exp: %q"+ + " got: %q", test.name, test.after, result) } } } diff --git a/txscript/scriptbuilder.go b/txscript/scriptbuilder.go index 5c1e76a6..420699bf 100644 --- a/txscript/scriptbuilder.go +++ b/txscript/scriptbuilder.go @@ -1,5 +1,5 @@ // Copyright (c) 2013-2015 The btcsuite developers -// Copyright (c) 2015-2016 The Decred developers +// Copyright (c) 2015-2018 The Decred developers // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. @@ -63,9 +63,9 @@ func (b *ScriptBuilder) AddOp(opcode byte) *ScriptBuilder { // Pushes that would cause the script to exceed the largest allowed // script size would result in a non-canonical script. - if len(b.script)+1 > maxScriptSize { + if len(b.script)+1 > MaxScriptSize { str := fmt.Sprintf("adding an opcode would exceed the maximum "+ - "allowed canonical script length of %d", maxScriptSize) + "allowed canonical script length of %d", MaxScriptSize) b.err = ErrScriptNotCanonical(str) return b } @@ -84,9 +84,9 @@ func (b *ScriptBuilder) AddOps(opcodes []byte) *ScriptBuilder { // Pushes that would cause the script to exceed the largest allowed // script size would result in a non-canonical script. - if len(b.script)+len(opcodes) > maxScriptSize { + if len(b.script)+len(opcodes) > MaxScriptSize { str := fmt.Sprintf("adding opcodes would exceed the maximum "+ - "allowed canonical script length of %d", maxScriptSize) + "allowed canonical script length of %d", MaxScriptSize) b.err = ErrScriptNotCanonical(str) return b } @@ -199,10 +199,10 @@ func (b *ScriptBuilder) AddData(data []byte) *ScriptBuilder { // Pushes that would cause the script to exceed the largest allowed // script size would result in a non-canonical script. dataSize := CanonicalDataSize(data) - if len(b.script)+dataSize > maxScriptSize { + if len(b.script)+dataSize > MaxScriptSize { str := fmt.Sprintf("adding %d bytes of data would exceed the "+ "maximum allowed canonical script length of %d", - dataSize, maxScriptSize) + dataSize, MaxScriptSize) b.err = ErrScriptNotCanonical(str) return b } @@ -213,7 +213,7 @@ func (b *ScriptBuilder) AddData(data []byte) *ScriptBuilder { if dataLen > MaxScriptElementSize { str := fmt.Sprintf("adding a data element of %d bytes would "+ "exceed the maximum allowed script element size of %d", - dataLen, maxScriptSize) + dataLen, MaxScriptElementSize) b.err = ErrScriptNotCanonical(str) return b } @@ -231,10 +231,10 @@ func (b *ScriptBuilder) AddInt64(val int64) *ScriptBuilder { // Pushes that would cause the script to exceed the largest allowed // script size would result in a non-canonical script. - if len(b.script)+1 > maxScriptSize { + if len(b.script)+1 > MaxScriptSize { str := fmt.Sprintf("adding an integer would exceed the "+ "maximum allow canonical script length of %d", - maxScriptSize) + MaxScriptSize) b.err = ErrScriptNotCanonical(str) return b } diff --git a/txscript/scriptbuilder_test.go b/txscript/scriptbuilder_test.go index 04a8274d..2ed12739 100644 --- a/txscript/scriptbuilder_test.go +++ b/txscript/scriptbuilder_test.go @@ -292,7 +292,7 @@ func TestExceedMaxScriptSize(t *testing.T) { // Start off by constructing a max size script. builder := NewScriptBuilder() - builder.Reset().AddFullData(make([]byte, maxScriptSize-3)) + builder.Reset().AddFullData(make([]byte, MaxScriptSize-3)) origScript, err := builder.Script() if err != nil { t.Fatalf("Unexpected error for max size script: %v", err) @@ -312,7 +312,7 @@ func TestExceedMaxScriptSize(t *testing.T) { // Ensure adding an opcode that would exceed the maximum size of the // script does not add the data. - builder.Reset().AddFullData(make([]byte, maxScriptSize-3)) + builder.Reset().AddFullData(make([]byte, MaxScriptSize-3)) script, err = builder.AddOp(OP_0).Script() if _, ok := err.(ErrScriptNotCanonical); !ok || err == nil { t.Fatalf("ScriptBuilder.AddOp unexpected modified script - "+ @@ -325,7 +325,7 @@ func TestExceedMaxScriptSize(t *testing.T) { // Ensure adding an integer that would exceed the maximum size of the // script does not add the data. - builder.Reset().AddFullData(make([]byte, maxScriptSize-3)) + builder.Reset().AddFullData(make([]byte, MaxScriptSize-3)) script, err = builder.AddInt64(0).Script() if _, ok := err.(ErrScriptNotCanonical); !ok || err == nil { t.Fatalf("ScriptBuilder.AddInt64 unexpected modified script - "+ @@ -346,7 +346,7 @@ func TestErroredScript(t *testing.T) { // space left to add each data type without an error and force an // initial error condition. builder := NewScriptBuilder() - builder.Reset().AddFullData(make([]byte, maxScriptSize-8)) + builder.Reset().AddFullData(make([]byte, MaxScriptSize-8)) origScript, err := builder.Script() if err != nil { t.Fatalf("ScriptBuilder.AddFullData unexpected error: %v", err) diff --git a/txscript/scriptnum.go b/txscript/scriptnum.go index 7c62aac2..64cdf984 100644 --- a/txscript/scriptnum.go +++ b/txscript/scriptnum.go @@ -1,10 +1,14 @@ -// Copyright (c) 2015 The btcsuite developers -// Copyright (c) 2015-2016 The Decred developers +// Copyright (c) 2015-2017 The btcsuite developers +// Copyright (c) 2015-2018 The Decred developers // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. package txscript +import ( + "fmt" +) + const ( maxInt32 = 1<<31 - 1 minInt32 = -1 << 31 @@ -66,7 +70,9 @@ func checkMinimalDataEncoding(v []byte) error { // is +-255, which encode to 0xff00 and 0xff80 respectively. // (big-endian). if len(v) == 1 || v[len(v)-2]&0x80 == 0 { - return ErrStackMinimalData + str := fmt.Sprintf("numeric value encoded as %x is "+ + "not minimally encoded", v) + return scriptError(ErrMinimalData, str) } } @@ -174,8 +180,8 @@ func (n scriptNum) Int32() int32 { // requireMinimal enabled. // // The scriptNumLen is the maximum number of bytes the encoded value can be -// before an ErrStackNumberTooBig is returned. This effectively limits the -// range of allowed values. +// before an ErrNumberTooBig is returned. This effectively limits the range of +// allowed values. // WARNING: Great care should be taken if passing a value larger than // defaultScriptNumLen, which could lead to addition and multiplication // overflows. @@ -185,7 +191,10 @@ func makeScriptNum(v []byte, requireMinimal bool, scriptNumLen int) (scriptNum, // Interpreting data requires that it is not larger than // the the passed scriptNumLen value. if len(v) > scriptNumLen { - return 0, ErrStackNumberTooBig + str := fmt.Sprintf("numeric value encoded as %x is %d bytes "+ + "which exceeds the max allowed of %d", v, len(v), + scriptNumLen) + return 0, scriptError(ErrNumOutOfRange, str) } // Enforce minimal encoded if requested. diff --git a/txscript/scriptnum_test.go b/txscript/scriptnum_test.go index 7d084e0a..36156aa2 100644 --- a/txscript/scriptnum_test.go +++ b/txscript/scriptnum_test.go @@ -1,5 +1,5 @@ -// Copyright (c) 2015 The btcsuite developers -// Copyright (c) 2015-2016 The Decred developers +// Copyright (c) 2015-2017 The btcsuite developers +// Copyright (c) 2015-2018 The Decred developers // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. @@ -92,6 +92,11 @@ func TestScriptNumBytes(t *testing.T) { func TestMakeScriptNum(t *testing.T) { t.Parallel() + // Errors used in the tests below defined here for convenience and to + // keep the horizontal test size shorter. + errOutOfRange := scriptError(ErrNumOutOfRange, "") + errMinimalData := scriptError(ErrMinimalData, "") + tests := []struct { serialized []byte num scriptNum @@ -100,7 +105,7 @@ func TestMakeScriptNum(t *testing.T) { err error }{ // Minimal encoding must reject negative 0. - {hexToBytes("80"), 0, mathOpCodeMaxScriptNumLen, true, ErrStackMinimalData}, + {hexToBytes("80"), 0, mathOpCodeMaxScriptNumLen, true, errMinimalData}, // Minimally encoded valid values with minimal encoding flag. // Should not error and return expected integral number. @@ -141,35 +146,35 @@ func TestMakeScriptNum(t *testing.T) { // Minimally encoded values that are out of range for data that // is interpreted as script numbers with the minimal encoding // flag set. Should error and return 0. - {hexToBytes("0000008000"), 0, mathOpCodeMaxScriptNumLen, true, ErrStackNumberTooBig}, - {hexToBytes("0000008080"), 0, mathOpCodeMaxScriptNumLen, true, ErrStackNumberTooBig}, - {hexToBytes("0000009000"), 0, mathOpCodeMaxScriptNumLen, true, ErrStackNumberTooBig}, - {hexToBytes("0000009080"), 0, mathOpCodeMaxScriptNumLen, true, ErrStackNumberTooBig}, - {hexToBytes("ffffffff00"), 0, mathOpCodeMaxScriptNumLen, true, ErrStackNumberTooBig}, - {hexToBytes("ffffffff80"), 0, mathOpCodeMaxScriptNumLen, true, ErrStackNumberTooBig}, - {hexToBytes("0000000001"), 0, mathOpCodeMaxScriptNumLen, true, ErrStackNumberTooBig}, - {hexToBytes("0000000081"), 0, mathOpCodeMaxScriptNumLen, true, ErrStackNumberTooBig}, - {hexToBytes("ffffffffffff00"), 0, mathOpCodeMaxScriptNumLen, true, ErrStackNumberTooBig}, - {hexToBytes("ffffffffffff80"), 0, mathOpCodeMaxScriptNumLen, true, ErrStackNumberTooBig}, - {hexToBytes("ffffffffffffff00"), 0, mathOpCodeMaxScriptNumLen, true, ErrStackNumberTooBig}, - {hexToBytes("ffffffffffffff80"), 0, mathOpCodeMaxScriptNumLen, true, ErrStackNumberTooBig}, - {hexToBytes("ffffffffffffff7f"), 0, mathOpCodeMaxScriptNumLen, true, ErrStackNumberTooBig}, - {hexToBytes("ffffffffffffffff"), 0, mathOpCodeMaxScriptNumLen, true, ErrStackNumberTooBig}, + {hexToBytes("0000008000"), 0, mathOpCodeMaxScriptNumLen, true, errOutOfRange}, + {hexToBytes("0000008080"), 0, mathOpCodeMaxScriptNumLen, true, errOutOfRange}, + {hexToBytes("0000009000"), 0, mathOpCodeMaxScriptNumLen, true, errOutOfRange}, + {hexToBytes("0000009080"), 0, mathOpCodeMaxScriptNumLen, true, errOutOfRange}, + {hexToBytes("ffffffff00"), 0, mathOpCodeMaxScriptNumLen, true, errOutOfRange}, + {hexToBytes("ffffffff80"), 0, mathOpCodeMaxScriptNumLen, true, errOutOfRange}, + {hexToBytes("0000000001"), 0, mathOpCodeMaxScriptNumLen, true, errOutOfRange}, + {hexToBytes("0000000081"), 0, mathOpCodeMaxScriptNumLen, true, errOutOfRange}, + {hexToBytes("ffffffffffff00"), 0, mathOpCodeMaxScriptNumLen, true, errOutOfRange}, + {hexToBytes("ffffffffffff80"), 0, mathOpCodeMaxScriptNumLen, true, errOutOfRange}, + {hexToBytes("ffffffffffffff00"), 0, mathOpCodeMaxScriptNumLen, true, errOutOfRange}, + {hexToBytes("ffffffffffffff80"), 0, mathOpCodeMaxScriptNumLen, true, errOutOfRange}, + {hexToBytes("ffffffffffffff7f"), 0, mathOpCodeMaxScriptNumLen, true, errOutOfRange}, + {hexToBytes("ffffffffffffffff"), 0, mathOpCodeMaxScriptNumLen, true, errOutOfRange}, // Non-minimally encoded, but otherwise valid values with // minimal encoding flag. Should error and return 0. - {hexToBytes("00"), 0, mathOpCodeMaxScriptNumLen, true, ErrStackMinimalData}, // 0 - {hexToBytes("0100"), 0, mathOpCodeMaxScriptNumLen, true, ErrStackMinimalData}, // 1 - {hexToBytes("7f00"), 0, mathOpCodeMaxScriptNumLen, true, ErrStackMinimalData}, // 127 - {hexToBytes("800000"), 0, mathOpCodeMaxScriptNumLen, true, ErrStackMinimalData}, // 128 - {hexToBytes("810000"), 0, mathOpCodeMaxScriptNumLen, true, ErrStackMinimalData}, // 129 - {hexToBytes("000100"), 0, mathOpCodeMaxScriptNumLen, true, ErrStackMinimalData}, // 256 - {hexToBytes("ff7f00"), 0, mathOpCodeMaxScriptNumLen, true, ErrStackMinimalData}, // 32767 - {hexToBytes("00800000"), 0, mathOpCodeMaxScriptNumLen, true, ErrStackMinimalData}, // 32768 - {hexToBytes("ffff0000"), 0, mathOpCodeMaxScriptNumLen, true, ErrStackMinimalData}, // 65535 - {hexToBytes("00000800"), 0, mathOpCodeMaxScriptNumLen, true, ErrStackMinimalData}, // 524288 - {hexToBytes("00007000"), 0, mathOpCodeMaxScriptNumLen, true, ErrStackMinimalData}, // 7340032 - {hexToBytes("0009000100"), 0, 5, true, ErrStackMinimalData}, // 16779520 + {hexToBytes("00"), 0, mathOpCodeMaxScriptNumLen, true, errMinimalData}, // 0 + {hexToBytes("0100"), 0, mathOpCodeMaxScriptNumLen, true, errMinimalData}, // 1 + {hexToBytes("7f00"), 0, mathOpCodeMaxScriptNumLen, true, errMinimalData}, // 127 + {hexToBytes("800000"), 0, mathOpCodeMaxScriptNumLen, true, errMinimalData}, // 128 + {hexToBytes("810000"), 0, mathOpCodeMaxScriptNumLen, true, errMinimalData}, // 129 + {hexToBytes("000100"), 0, mathOpCodeMaxScriptNumLen, true, errMinimalData}, // 256 + {hexToBytes("ff7f00"), 0, mathOpCodeMaxScriptNumLen, true, errMinimalData}, // 32767 + {hexToBytes("00800000"), 0, mathOpCodeMaxScriptNumLen, true, errMinimalData}, // 32768 + {hexToBytes("ffff0000"), 0, mathOpCodeMaxScriptNumLen, true, errMinimalData}, // 65535 + {hexToBytes("00000800"), 0, mathOpCodeMaxScriptNumLen, true, errMinimalData}, // 524288 + {hexToBytes("00007000"), 0, mathOpCodeMaxScriptNumLen, true, errMinimalData}, // 7340032 + {hexToBytes("0009000100"), 0, 5, true, errMinimalData}, // 16779520 // Non-minimally encoded, but otherwise valid values without // minimal encoding flag. Should not error and return expected @@ -189,18 +194,18 @@ func TestMakeScriptNum(t *testing.T) { } for _, test := range tests { + // Ensure the error code is of the expected type and the error + // code matches the value specified in the test instance. gotNum, err := makeScriptNum(test.serialized, test.minimalEncoding, test.numLen) - if err != test.err { - t.Errorf("makeScriptNum: did not received expected "+ - "error for %x - got %v, want %v", - test.serialized, err, test.err) + if e := tstCheckScriptError(err, test.err); e != nil { + t.Errorf("makeScriptNum(%#x): %v", test.serialized, e) continue } if gotNum != test.num { - t.Errorf("makeScriptNum: did not get expected number "+ - "for %x - got %d, want %d", test.serialized, + t.Errorf("makeScriptNum(%#x): did not get expected "+ + "number - got %d, want %d", test.serialized, gotNum, test.num) continue } diff --git a/txscript/sighash.go b/txscript/sighash.go index 4e939937..1de0c639 100644 --- a/txscript/sighash.go +++ b/txscript/sighash.go @@ -7,6 +7,7 @@ package txscript import ( "encoding/binary" + "fmt" "math" "github.com/decred/dcrd/chaincfg" @@ -234,7 +235,9 @@ func calcSignatureHash(prevOutScript []parsedOpcode, hashType SigHashType, tx *w // is improper to use SigHashSingle on input indices that don't have a // corresponding output. if hashType&sigHashMask == SigHashSingle && idx >= len(tx.TxOut) { - return nil, ErrSighashSingleIdx + str := fmt.Sprintf("attempt to sign single input at index %d "+ + ">= %d outputs", idx, len(tx.TxOut)) + return nil, scriptError(ErrInvalidSigHashSingleIndex, str) } // Remove all instances of OP_CODESEPARATOR from the script. diff --git a/txscript/stack.go b/txscript/stack.go index ba2c6e85..a2bae906 100644 --- a/txscript/stack.go +++ b/txscript/stack.go @@ -1,11 +1,14 @@ -// Copyright (c) 2013-2015 The btcsuite developers -// Copyright (c) 2015-2016 The Decred developers +// Copyright (c) 2013-2017 The btcsuite developers +// Copyright (c) 2015-2018 The Decred developers // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. package txscript -import "encoding/hex" +import ( + "encoding/hex" + "fmt" +) // asBool gets the boolean value of the byte array. func asBool(t []byte) bool { @@ -104,7 +107,9 @@ func (s *stack) PopBool() (bool, error) { func (s *stack) PeekByteArray(idx int32) ([]byte, error) { sz := int32(len(s.stk)) if idx < 0 || idx >= sz { - return nil, ErrStackUnderflow + str := fmt.Sprintf("index %d is invalid for stack size %d", idx, + sz) + return nil, scriptError(ErrInvalidStackOperation, str) } return s.stk[sz-idx-1], nil @@ -142,7 +147,9 @@ func (s *stack) PeekBool(idx int32) (bool, error) { func (s *stack) nipN(idx int32) ([]byte, error) { sz := int32(len(s.stk)) if idx < 0 || idx > sz-1 { - return nil, ErrStackUnderflow + str := fmt.Sprintf("index %d is invalid for stack size %d", idx, + sz) + return nil, scriptError(ErrInvalidStackOperation, str) } so := s.stk[sz-idx-1] @@ -198,7 +205,8 @@ func (s *stack) Tuck() error { // DropN(2): [... x1 x2] -> [...] func (s *stack) DropN(n int32) error { if n < 1 { - return ErrStackInvalidArgs + str := fmt.Sprintf("attempt to drop %d items from stack", n) + return scriptError(ErrInvalidStackOperation, str) } for ; n > 0; n-- { @@ -217,7 +225,8 @@ func (s *stack) DropN(n int32) error { // DupN(2): [... x1 x2] -> [... x1 x2 x1 x2] func (s *stack) DupN(n int32) error { if n < 1 { - return ErrStackInvalidArgs + str := fmt.Sprintf("attempt to dup %d stack items", n) + return scriptError(ErrInvalidStackOperation, str) } // Iteratively duplicate the value n-1 down the stack n times. @@ -239,7 +248,8 @@ func (s *stack) DupN(n int32) error { // RotN(2): [... x1 x2 x3 x4 x5 x6] -> [... x3 x4 x5 x6 x1 x2] func (s *stack) RotN(n int32) error { if n < 1 { - return ErrStackInvalidArgs + str := fmt.Sprintf("attempt to rotate %d stack items", n) + return scriptError(ErrInvalidStackOperation, str) } // Nip the 3n-1th item from the stack to the top n times to rotate @@ -263,7 +273,8 @@ func (s *stack) RotN(n int32) error { // SwapN(2): [... x1 x2 x3 x4] -> [... x3 x4 x1 x2] func (s *stack) SwapN(n int32) error { if n < 1 { - return ErrStackInvalidArgs + str := fmt.Sprintf("attempt to swap %d stack items", n) + return scriptError(ErrInvalidStackOperation, str) } entry := 2*n - 1 @@ -286,7 +297,9 @@ func (s *stack) SwapN(n int32) error { // OverN(2): [... x1 x2 x3 x4] -> [... x1 x2 x3 x4 x1 x2] func (s *stack) OverN(n int32) error { if n < 1 { - return ErrStackInvalidArgs + str := fmt.Sprintf("attempt to perform over on %d stack items", + n) + return scriptError(ErrInvalidStackOperation, str) } // Copy 2n-1th entry to top of the stack. diff --git a/txscript/stack_test.go b/txscript/stack_test.go index 2f90aac0..70ab073a 100644 --- a/txscript/stack_test.go +++ b/txscript/stack_test.go @@ -1,5 +1,5 @@ -// Copyright (c) 2013-2015 The btcsuite developers -// Copyright (c) 2015-2016 The Decred developers +// Copyright (c) 2013-2017 The btcsuite developers +// Copyright (c) 2015-2018 The Decred developers // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. @@ -9,19 +9,52 @@ import ( "bytes" "errors" "fmt" + "reflect" "testing" ) +// tstCheckScriptError ensures the type of the two passed errors are of the +// same type (either both nil or both of type Error) and their error codes +// match when not nil. +func tstCheckScriptError(gotErr, wantErr error) error { + // Ensure the error code is of the expected type and the error + // code matches the value specified in the test instance. + if reflect.TypeOf(gotErr) != reflect.TypeOf(wantErr) { + return fmt.Errorf("wrong error - got %T (%[1]v), want %T", + gotErr, wantErr) + } + if gotErr == nil { + return nil + } + + // Ensure the want error type is a script error. + werr, ok := wantErr.(Error) + if !ok { + return fmt.Errorf("unexpected test error type %T", wantErr) + } + + // Ensure the error codes match. It's safe to use a raw type assert + // here since the code above already proved they are the same type and + // the want error is a script error. + gotErrorCode := gotErr.(Error).ErrorCode + if gotErrorCode != werr.ErrorCode { + return fmt.Errorf("mismatched error code - got %v (%v), want %v", + gotErrorCode, gotErr, werr.ErrorCode) + } + + return nil +} + // TestStack tests that all of the stack operations work as expected. func TestStack(t *testing.T) { t.Parallel() tests := []struct { - name string - before [][]byte - operation func(*stack) error - expectedReturn error - after [][]byte + name string + before [][]byte + operation func(*stack) error + err error + after [][]byte }{ { "noop", @@ -39,7 +72,7 @@ func TestStack(t *testing.T) { _, err := s.PeekByteArray(5) return err }, - ErrStackUnderflow, + scriptError(ErrInvalidStackOperation, ""), nil, }, { @@ -49,7 +82,7 @@ func TestStack(t *testing.T) { _, err := s.PeekInt(5) return err }, - ErrStackUnderflow, + scriptError(ErrInvalidStackOperation, ""), nil, }, { @@ -59,7 +92,7 @@ func TestStack(t *testing.T) { _, err := s.PeekBool(5) return err }, - ErrStackUnderflow, + scriptError(ErrInvalidStackOperation, ""), nil, }, { @@ -105,7 +138,7 @@ func TestStack(t *testing.T) { } return nil }, - ErrStackUnderflow, + scriptError(ErrInvalidStackOperation, ""), nil, }, { @@ -149,7 +182,7 @@ func TestStack(t *testing.T) { _, err := s.PopBool() return err }, - ErrStackUnderflow, + scriptError(ErrInvalidStackOperation, ""), nil, }, { @@ -371,7 +404,7 @@ func TestStack(t *testing.T) { func(s *stack) error { return s.DupN(0) }, - ErrStackInvalidArgs, + scriptError(ErrInvalidStackOperation, ""), nil, }, { @@ -380,7 +413,7 @@ func TestStack(t *testing.T) { func(s *stack) error { return s.DupN(-1) }, - ErrStackInvalidArgs, + scriptError(ErrInvalidStackOperation, ""), nil, }, { @@ -389,7 +422,7 @@ func TestStack(t *testing.T) { func(s *stack) error { return s.DupN(2) }, - ErrStackUnderflow, + scriptError(ErrInvalidStackOperation, ""), nil, }, { @@ -520,7 +553,7 @@ func TestStack(t *testing.T) { // bite off more than we can chew return s.NipN(3) }, - ErrStackUnderflow, + scriptError(ErrInvalidStackOperation, ""), [][]byte{{2}, {3}}, }, { @@ -538,7 +571,7 @@ func TestStack(t *testing.T) { func(s *stack) error { return s.Tuck() }, - ErrStackUnderflow, + scriptError(ErrInvalidStackOperation, ""), nil, }, { @@ -547,7 +580,7 @@ func TestStack(t *testing.T) { func(s *stack) error { return s.Tuck() }, - ErrStackUnderflow, + scriptError(ErrInvalidStackOperation, ""), nil, }, { @@ -592,7 +625,7 @@ func TestStack(t *testing.T) { func(s *stack) error { return s.DropN(5) }, - ErrStackUnderflow, + scriptError(ErrInvalidStackOperation, ""), nil, }, { @@ -601,7 +634,7 @@ func TestStack(t *testing.T) { func(s *stack) error { return s.DropN(0) }, - ErrStackInvalidArgs, + scriptError(ErrInvalidStackOperation, ""), nil, }, { @@ -628,7 +661,7 @@ func TestStack(t *testing.T) { func(s *stack) error { return s.RotN(1) }, - ErrStackUnderflow, + scriptError(ErrInvalidStackOperation, ""), nil, }, { @@ -637,7 +670,7 @@ func TestStack(t *testing.T) { func(s *stack) error { return s.RotN(0) }, - ErrStackInvalidArgs, + scriptError(ErrInvalidStackOperation, ""), nil, }, { @@ -664,7 +697,7 @@ func TestStack(t *testing.T) { func(s *stack) error { return s.SwapN(1) }, - ErrStackUnderflow, + scriptError(ErrInvalidStackOperation, ""), nil, }, { @@ -673,7 +706,7 @@ func TestStack(t *testing.T) { func(s *stack) error { return s.SwapN(0) }, - ErrStackInvalidArgs, + scriptError(ErrInvalidStackOperation, ""), nil, }, { @@ -700,7 +733,7 @@ func TestStack(t *testing.T) { func(s *stack) error { return s.OverN(1) }, - ErrStackUnderflow, + scriptError(ErrInvalidStackOperation, ""), nil, }, { @@ -709,7 +742,7 @@ func TestStack(t *testing.T) { func(s *stack) error { return s.OverN(0) }, - ErrStackInvalidArgs, + scriptError(ErrInvalidStackOperation, ""), nil, }, { @@ -736,7 +769,7 @@ func TestStack(t *testing.T) { func(s *stack) error { return s.PickN(1) }, - ErrStackUnderflow, + scriptError(ErrInvalidStackOperation, ""), nil, }, { @@ -763,7 +796,7 @@ func TestStack(t *testing.T) { func(s *stack) error { return s.RollN(1) }, - ErrStackUnderflow, + scriptError(ErrInvalidStackOperation, ""), nil, }, { @@ -866,32 +899,39 @@ func TestStack(t *testing.T) { _, err := s.PopInt(mathOpCodeMaxScriptNumLen) return err }, - ErrStackUnderflow, + scriptError(ErrInvalidStackOperation, ""), nil, }, } for _, test := range tests { + // Setup the initial stack state and perform the test operation. s := stack{} - for i := range test.before { s.PushByteArray(test.before[i]) } err := test.operation(&s) - if err != test.expectedReturn { - t.Errorf("%s: operation return not what expected: %v "+ - "vs %v", test.name, err, test.expectedReturn) + + // Ensure the error code is of the expected type and the error + // code matches the value specified in the test instance. + if e := tstCheckScriptError(err, test.err); e != nil { + t.Errorf("%s: %v", test.name, e) + continue } if err != nil { continue } + // Ensure the resulting stack is the expected length. if int32(len(test.after)) != s.Depth() { t.Errorf("%s: stack depth doesn't match expected: %v "+ "vs %v", test.name, len(test.after), s.Depth()) + continue } + // Ensure all items of the resulting stack are the expected + // values. for i := range test.after { val, err := s.PeekByteArray(s.Depth() - int32(i) - 1) if err != nil { diff --git a/txscript/standard.go b/txscript/standard.go index 33f64aa8..5caab8d7 100644 --- a/txscript/standard.go +++ b/txscript/standard.go @@ -1,5 +1,5 @@ -// Copyright (c) 2013-2015 The btcsuite developers -// Copyright (c) 2015-2016 The Decred developers +// Copyright (c) 2013-2017 The btcsuite developers +// Copyright (c) 2015-2018 The Decred developers // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. @@ -19,6 +19,11 @@ const ( // MaxDataCarrierSize is the maximum number of bytes allowed in pushed // data to be considered a nulldata transaction. MaxDataCarrierSize = 256 + + // nilAddrErrStr is the common error string to use for attempts to + // generate payment scripts to nil addresses embedded within a + // dcrutil.Address interface. + nilAddrErrStr = "unable to generate payment script for nil address" ) // ScriptClass is an enumeration for the list of standard types of script. @@ -521,9 +526,10 @@ func CalcScriptInfo(sigScript, pkScript []byte, bip16 bool) (*ScriptInfo, error) si := new(ScriptInfo) si.PkScriptClass = typeOfScript(pkPops) - // Can't have a pkScript that doesn't just push data. + // Can't have a signature script that doesn't just push data. if !isPushOnly(sigPops) { - return nil, ErrStackNonPushOnly + return nil, scriptError(ErrNotPushOnly, + "signature script is not push only") } subClass := ScriptClass(0) @@ -583,7 +589,8 @@ func CalcMultiSigStats(script []byte) (int, int, error) { // items must be on the stack per: // OP_1 PUBKEY OP_1 OP_CHECKMULTISIG if len(pops) < 4 { - return 0, 0, ErrStackUnderflow + str := fmt.Sprintf("script %x is not a multisig script", script) + return 0, 0, scriptError(ErrNotMultisigScript, str) } numSigs := asSmallInt(pops[0].opcode) @@ -699,22 +706,32 @@ func payToSchnorrPubKeyScript(serializedPubKey []byte) ([]byte, error) { // public key hash, but tags the output with OP_SSTX. For use in constructing // valid SStxs. func PayToSStx(addr dcrutil.Address) ([]byte, error) { - if addr == nil { - return nil, ErrUnsupportedAddress - } - // Only pay to pubkey hash and pay to script hash are // supported. scriptType := PubKeyHashTy switch addr := addr.(type) { case *dcrutil.AddressPubKeyHash: - if addr.DSA(addr.Net()) != chainec.ECTypeSecp256k1 { - return nil, ErrUnsupportedAddress + if addr == nil { + return nil, scriptError(ErrUnsupportedAddress, + nilAddrErrStr) } + if addr.DSA(addr.Net()) != chainec.ECTypeSecp256k1 { + str := "unable to generate payment script for " + + "unsupported digital signature algorithm" + return nil, scriptError(ErrUnsupportedAddress, str) + } + case *dcrutil.AddressScriptHash: + if addr == nil { + return nil, scriptError(ErrUnsupportedAddress, + nilAddrErrStr) + } scriptType = ScriptHashTy + default: - return nil, ErrUnsupportedAddress + str := fmt.Sprintf("unable to generate payment script for "+ + "unsupported address type %T", addr) + return nil, scriptError(ErrUnsupportedAddress, str) } hash := addr.ScriptAddress() @@ -732,22 +749,32 @@ func PayToSStx(addr dcrutil.Address) ([]byte, error) { // public key hash, but tags the output with OP_SSTXCHANGE. For use in constructing // valid SStxs. func PayToSStxChange(addr dcrutil.Address) ([]byte, error) { - if addr == nil { - return nil, ErrUnsupportedAddress - } - // Only pay to pubkey hash and pay to script hash are // supported. scriptType := PubKeyHashTy switch addr := addr.(type) { case *dcrutil.AddressPubKeyHash: - if addr.DSA(addr.Net()) != chainec.ECTypeSecp256k1 { - return nil, ErrUnsupportedAddress + if addr == nil { + return nil, scriptError(ErrUnsupportedAddress, + nilAddrErrStr) } + if addr.DSA(addr.Net()) != chainec.ECTypeSecp256k1 { + str := "unable to generate payment script for " + + "unsupported digital signature algorithm" + return nil, scriptError(ErrUnsupportedAddress, str) + } + case *dcrutil.AddressScriptHash: + if addr == nil { + return nil, scriptError(ErrUnsupportedAddress, + nilAddrErrStr) + } scriptType = ScriptHashTy + default: - return nil, ErrUnsupportedAddress + str := fmt.Sprintf("unable to generate payment script for "+ + "unsupported address type %T", addr) + return nil, scriptError(ErrUnsupportedAddress, str) } hash := addr.ScriptAddress() @@ -765,22 +792,32 @@ func PayToSStxChange(addr dcrutil.Address) ([]byte, error) { // hash or script hash, but tags the output with OP_SSGEN. For use in constructing // valid SSGen txs. func PayToSSGen(addr dcrutil.Address) ([]byte, error) { - if addr == nil { - return nil, ErrUnsupportedAddress - } - // Only pay to pubkey hash and pay to script hash are // supported. scriptType := PubKeyHashTy switch addr := addr.(type) { case *dcrutil.AddressPubKeyHash: - if addr.DSA(addr.Net()) != chainec.ECTypeSecp256k1 { - return nil, ErrUnsupportedAddress + if addr == nil { + return nil, scriptError(ErrUnsupportedAddress, + nilAddrErrStr) } + if addr.DSA(addr.Net()) != chainec.ECTypeSecp256k1 { + str := "unable to generate payment script for " + + "unsupported digital signature algorithm" + return nil, scriptError(ErrUnsupportedAddress, str) + } + case *dcrutil.AddressScriptHash: + if addr == nil { + return nil, scriptError(ErrUnsupportedAddress, + nilAddrErrStr) + } scriptType = ScriptHashTy + default: - return nil, ErrUnsupportedAddress + str := fmt.Sprintf("unable to generate payment script for "+ + "unsupported address type %T", addr) + return nil, scriptError(ErrUnsupportedAddress, str) } hash := addr.ScriptAddress() @@ -799,10 +836,6 @@ func PayToSSGen(addr dcrutil.Address) ([]byte, error) { // valid SSGen txs. Unlike PayToSSGen, this function directly uses the HASH160 // pubkeyhash (instead of an address). func PayToSSGenPKHDirect(pkh []byte) ([]byte, error) { - if pkh == nil { - return nil, ErrUnsupportedAddress - } - return NewScriptBuilder().AddOp(OP_SSGEN).AddOp(OP_DUP). AddOp(OP_HASH160).AddData(pkh).AddOp(OP_EQUALVERIFY). AddOp(OP_CHECKSIG).Script() @@ -813,10 +846,6 @@ func PayToSSGenPKHDirect(pkh []byte) ([]byte, error) { // valid SSGen txs. Unlike PayToSSGen, this function directly uses the HASH160 // script hash (instead of an address). func PayToSSGenSHDirect(sh []byte) ([]byte, error) { - if sh == nil { - return nil, ErrUnsupportedAddress - } - return NewScriptBuilder().AddOp(OP_SSGEN).AddOp(OP_HASH160). AddData(sh).AddOp(OP_EQUAL).Script() } @@ -825,22 +854,32 @@ func PayToSSGenSHDirect(sh []byte) ([]byte, error) { // public key hash, but tags the output with OP_SSRTX. For use in constructing // valid SSRtx. func PayToSSRtx(addr dcrutil.Address) ([]byte, error) { - if addr == nil { - return nil, ErrUnsupportedAddress - } - // Only pay to pubkey hash and pay to script hash are // supported. scriptType := PubKeyHashTy switch addr := addr.(type) { case *dcrutil.AddressPubKeyHash: - if addr.DSA(addr.Net()) != chainec.ECTypeSecp256k1 { - return nil, ErrUnsupportedAddress + if addr == nil { + return nil, scriptError(ErrUnsupportedAddress, + nilAddrErrStr) } + if addr.DSA(addr.Net()) != chainec.ECTypeSecp256k1 { + str := "unable to generate payment script for " + + "unsupported digital signature algorithm" + return nil, scriptError(ErrUnsupportedAddress, str) + } + case *dcrutil.AddressScriptHash: + if addr == nil { + return nil, scriptError(ErrUnsupportedAddress, + nilAddrErrStr) + } scriptType = ScriptHashTy + default: - return nil, ErrUnsupportedAddress + str := fmt.Sprintf("unable to generate payment script for "+ + "unsupported address type %T", addr) + return nil, scriptError(ErrUnsupportedAddress, str) } hash := addr.ScriptAddress() @@ -859,10 +898,6 @@ func PayToSSRtx(addr dcrutil.Address) ([]byte, error) { // valid SSRtx. Unlike PayToSSRtx, this function directly uses the HASH160 // pubkeyhash (instead of an address). func PayToSSRtxPKHDirect(pkh []byte) ([]byte, error) { - if pkh == nil { - return nil, ErrUnsupportedAddress - } - return NewScriptBuilder().AddOp(OP_SSRTX).AddOp(OP_DUP). AddOp(OP_HASH160).AddData(pkh).AddOp(OP_EQUALVERIFY). AddOp(OP_CHECKSIG).Script() @@ -873,34 +908,39 @@ func PayToSSRtxPKHDirect(pkh []byte) ([]byte, error) { // valid SSRtx. Unlike PayToSSRtx, this function directly uses the HASH160 // script hash (instead of an address). func PayToSSRtxSHDirect(sh []byte) ([]byte, error) { - if sh == nil { - return nil, ErrUnsupportedAddress - } - return NewScriptBuilder().AddOp(OP_SSRTX).AddOp(OP_HASH160). AddData(sh).AddOp(OP_EQUAL).Script() } // GenerateSStxAddrPush generates an OP_RETURN push for SSGen payment addresses in // an SStx. -func GenerateSStxAddrPush(addr dcrutil.Address, amount dcrutil.Amount, - limits uint16) ([]byte, error) { - if addr == nil { - return nil, ErrUnsupportedAddress - } - +func GenerateSStxAddrPush(addr dcrutil.Address, amount dcrutil.Amount, limits uint16) ([]byte, error) { // Only pay to pubkey hash and pay to script hash are // supported. scriptType := PubKeyHashTy switch addr := addr.(type) { case *dcrutil.AddressPubKeyHash: - if addr.DSA(addr.Net()) != chainec.ECTypeSecp256k1 { - return nil, ErrUnsupportedAddress + if addr == nil { + return nil, scriptError(ErrUnsupportedAddress, + nilAddrErrStr) } + if addr.DSA(addr.Net()) != chainec.ECTypeSecp256k1 { + str := "unable to generate payment script for " + + "unsupported digital signature algorithm" + return nil, scriptError(ErrUnsupportedAddress, str) + } + case *dcrutil.AddressScriptHash: + if addr == nil { + return nil, scriptError(ErrUnsupportedAddress, + nilAddrErrStr) + } scriptType = ScriptHashTy + default: - return nil, ErrUnsupportedAddress + str := fmt.Sprintf("unable to generate payment script for "+ + "unsupported address type %T", addr) + return nil, scriptError(ErrUnsupportedAddress, str) } // Prefix @@ -932,8 +972,7 @@ func GenerateSStxAddrPush(addr dcrutil.Address, amount dcrutil.Amount, // GenerateSSGenBlockRef generates an OP_RETURN push for the block header hash and // height which the block votes on. -func GenerateSSGenBlockRef(blockHash chainhash.Hash, height uint32) ([]byte, - error) { +func GenerateSSGenBlockRef(blockHash chainhash.Hash, height uint32) ([]byte, error) { // Prefix dataPushes := []byte{ 0x6a, // OP_RETURN @@ -970,10 +1009,15 @@ func GenerateSSGenVotes(votebits uint16) ([]byte, error) { return voteBitsOut, nil } -// GenerateProvablyPruneableOut creates an OP_RETURN push of arbitrary data. +// GenerateProvablyPruneableOut creates a provably-prunable script containing +// OP_RETURN followed by the passed data. An Error with the error code +// ErrTooMuchNullData will be returned if the length of the passed data exceeds +// MaxDataCarrierSize. func GenerateProvablyPruneableOut(data []byte) ([]byte, error) { if len(data) > MaxDataCarrierSize { - return nil, ErrStackLongScript + str := fmt.Sprintf("data size %d is larger than max "+ + "allowed size %d", len(data), MaxDataCarrierSize) + return nil, scriptError(ErrTooMuchNullData, str) } return NewScriptBuilder().AddOp(OP_RETURN).AddData(data).Script() @@ -985,7 +1029,8 @@ func PayToAddrScript(addr dcrutil.Address) ([]byte, error) { switch addr := addr.(type) { case *dcrutil.AddressPubKeyHash: if addr == nil { - return nil, ErrUnsupportedAddress + return nil, scriptError(ErrUnsupportedAddress, + nilAddrErrStr) } switch addr.DSA(addr.Net()) { case chainec.ECTypeSecp256k1: @@ -998,40 +1043,48 @@ func PayToAddrScript(addr dcrutil.Address) ([]byte, error) { case *dcrutil.AddressScriptHash: if addr == nil { - return nil, ErrUnsupportedAddress + return nil, scriptError(ErrUnsupportedAddress, + nilAddrErrStr) } return payToScriptHashScript(addr.ScriptAddress()) case *dcrutil.AddressSecpPubKey: if addr == nil { - return nil, ErrUnsupportedAddress + return nil, scriptError(ErrUnsupportedAddress, + nilAddrErrStr) } return payToPubKeyScript(addr.ScriptAddress()) case *dcrutil.AddressEdwardsPubKey: if addr == nil { - return nil, ErrUnsupportedAddress + return nil, scriptError(ErrUnsupportedAddress, + nilAddrErrStr) } return payToEdwardsPubKeyScript(addr.ScriptAddress()) case *dcrutil.AddressSecSchnorrPubKey: if addr == nil { - return nil, ErrUnsupportedAddress + return nil, scriptError(ErrUnsupportedAddress, + nilAddrErrStr) } return payToSchnorrPubKeyScript(addr.ScriptAddress()) } - return nil, ErrUnsupportedAddress + str := fmt.Sprintf("unable to generate payment script for unsupported "+ + "address type %T", addr) + return nil, scriptError(ErrUnsupportedAddress, str) } // MultiSigScript returns a valid script for a multisignature redemption where // nrequired of the keys in pubkeys are required to have signed the transaction -// for success. An ErrBadNumRequired will be returned if nrequired is larger -// than the number of keys provided. -func MultiSigScript(pubkeys []*dcrutil.AddressSecpPubKey, nrequired int) ([]byte, - error) { +// for success. An Error with the error code ErrTooManyRequiredSigs will be +// returned if nrequired is larger than the number of keys provided. +func MultiSigScript(pubkeys []*dcrutil.AddressSecpPubKey, nrequired int) ([]byte, error) { if len(pubkeys) < nrequired { - return nil, ErrBadNumRequired + str := fmt.Sprintf("unable to generate multisig script with "+ + "%d required signatures when there are only %d public "+ + "keys available", nrequired, len(pubkeys)) + return nil, scriptError(ErrTooManyRequiredSigs, str) } builder := NewScriptBuilder().AddInt64(int64(nrequired)) diff --git a/txscript/standard_test.go b/txscript/standard_test.go index dea4eed7..1619a7a2 100644 --- a/txscript/standard_test.go +++ b/txscript/standard_test.go @@ -1,4 +1,4 @@ -// Copyright (c) 2013-2015 The btcsuite developers +// Copyright (c) 2013-2017 The btcsuite developers // Copyright (c) 2015-2018 The Decred developers // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. @@ -372,7 +372,7 @@ func TestCalcScriptInfo(t *testing.T) { pkScript: "HASH160 DATA_20 0xfe441065b6532231de2fac56" + "3152205ec4f59c", bip16: true, - scriptInfoErr: ErrStackShortScript, + scriptInfoErr: scriptError(ErrMalformedPush, ""), }, { name: "sigScript doesn't parse", @@ -382,7 +382,7 @@ func TestCalcScriptInfo(t *testing.T) { pkScript: "HASH160 DATA_20 0xfe441065b6532231de2fac56" + "3152205ec4f59c74 EQUAL", bip16: true, - scriptInfoErr: ErrStackShortScript, + scriptInfoErr: scriptError(ErrMalformedPush, ""), }, { // Invented scripts, the hashes do not match @@ -442,23 +442,18 @@ func TestCalcScriptInfo(t *testing.T) { sigScript := mustParseShortForm(test.sigScript) pkScript := mustParseShortForm(test.pkScript) si, err := CalcScriptInfo(sigScript, pkScript, test.bip16) + if e := tstCheckScriptError(err, test.scriptInfoErr); e != nil { + t.Errorf("scriptinfo test %q: %v", test.name, e) + continue + } if err != nil { - if err != test.scriptInfoErr { - t.Errorf("scriptinfo test \"%s\": got \"%v\""+ - "expected \"%v\"", test.name, err, - test.scriptInfoErr) - } - continue - } - if test.scriptInfoErr != nil { - t.Errorf("%s: succeeded when expecting \"%v\"", - test.name, test.scriptInfoErr) continue } + if *si != test.scriptInfo { t.Errorf("%s: scriptinfo doesn't match expected. "+ - "got: \"%v\" expected \"%v\"", test.name, - *si, test.scriptInfo) + "got: %q expected %q", test.name, *si, + test.scriptInfo) continue } } @@ -517,8 +512,7 @@ func TestPayToAddrScript(t *testing.T) { "373273efcc54ce7d2a491bb4a0e84"), &chaincfg.MainNetParams, chainec.ECTypeSecp256k1) if err != nil { - t.Errorf("Unable to create public key hash address: %v", err) - return + t.Fatalf("Unable to create public key hash address: %v", err) } // Taken from transaction: @@ -526,8 +520,7 @@ func TestPayToAddrScript(t *testing.T) { p2shMain, _ := dcrutil.NewAddressScriptHashFromHash(hexToBytes("e8c30"+ "0c87986efa84c37c0519929019ef86eb5b4"), &chaincfg.MainNetParams) if err != nil { - t.Errorf("Unable to create script hash address: %v", err) - return + t.Fatalf("Unable to create script hash address: %v", err) } // mainnet p2pk 13CG6SJ3yHUXo4Cr2RY4THLLJrNFuG3gUg @@ -535,23 +528,25 @@ func TestPayToAddrScript(t *testing.T) { "4d0cb94344c9569c2e77901573d8d7903c3ebec3a957724895dca52c6b4"), &chaincfg.MainNetParams) if err != nil { - t.Errorf("Unable to create pubkey address (compressed): %v", + t.Fatalf("Unable to create pubkey address (compressed): %v", err) - return } p2pkCompressed2Main, err := dcrutil.NewAddressSecpPubKey(hexToBytes("03b0b"+ "d634234abbb1ba1e986e884185c61cf43e001f9137f23c2c409273eb16e65"), &chaincfg.MainNetParams) if err != nil { - t.Errorf("Unable to create pubkey address (compressed 2): %v", + t.Fatalf("Unable to create pubkey address (compressed 2): %v", err) - return } p2pkUncompressedMain := newAddressPubKey(hexToBytes("0411db" + "93e1dcdb8a016b49840f8c53bc1eb68a382e97b1482ecad7b148a6909a5cb2" + "e0eaddfb84ccf9744464f82e160bfa9b8b64f9d4c03f999b8643f656b412a3")) + // Errors used in the tests below defined here for convenience and to + // keep the horizontal test size shorter. + errUnsupportedAddress := scriptError(ErrUnsupportedAddress, "") + tests := []struct { in dcrutil.Address expected string @@ -596,18 +591,20 @@ func TestPayToAddrScript(t *testing.T) { }, // Supported address types with nil pointers. - {(*dcrutil.AddressPubKeyHash)(nil), "", ErrUnsupportedAddress}, - {(*dcrutil.AddressScriptHash)(nil), "", ErrUnsupportedAddress}, - {(*dcrutil.AddressSecpPubKey)(nil), "", ErrUnsupportedAddress}, + {(*dcrutil.AddressPubKeyHash)(nil), "", errUnsupportedAddress}, + {(*dcrutil.AddressScriptHash)(nil), "", errUnsupportedAddress}, + {(*dcrutil.AddressSecpPubKey)(nil), "", errUnsupportedAddress}, + {(*dcrutil.AddressEdwardsPubKey)(nil), "", errUnsupportedAddress}, + {(*dcrutil.AddressSecSchnorrPubKey)(nil), "", errUnsupportedAddress}, // Unsupported address type. - {&bogusAddress{}, "", ErrUnsupportedAddress}, + {&bogusAddress{}, "", errUnsupportedAddress}, } t.Logf("Running %d tests", len(tests)) for i, test := range tests { pkScript, err := PayToAddrScript(test.in) - if err != test.err { + if e := tstCheckScriptError(err, test.err); e != nil { t.Errorf("PayToAddrScript #%d unexpected error - "+ "got %v, want %v", i, err, test.err) continue @@ -632,17 +629,15 @@ func TestMultiSigScript(t *testing.T) { "74d0cb94344c9569c2e77901573d8d7903c3ebec3a957724895dca52c6b4"), &chaincfg.MainNetParams) if err != nil { - t.Errorf("Unable to create pubkey address (compressed): %v", + t.Fatalf("Unable to create pubkey address (compressed): %v", err) - return } p2pkCompressed2Main, err := dcrutil.NewAddressSecpPubKey(hexToBytes("03b0b"+ "d634234abbb1ba1e986e884185c61cf43e001f9137f23c2c409273eb16e65"), &chaincfg.MainNetParams) if err != nil { - t.Errorf("Unable to create pubkey address (compressed 2): %v", + t.Fatalf("Unable to create pubkey address (compressed 2): %v", err) - return } p2pkUncompressedMain := newAddressPubKey(hexToBytes("0411d" + @@ -687,7 +682,7 @@ func TestMultiSigScript(t *testing.T) { }, 3, "", - ErrBadNumRequired, + scriptError(ErrTooManyRequiredSigs, ""), }, { // By default compressed pubkeys are used in Decred. @@ -705,16 +700,15 @@ func TestMultiSigScript(t *testing.T) { }, 2, "", - ErrBadNumRequired, + scriptError(ErrTooManyRequiredSigs, ""), }, } t.Logf("Running %d tests", len(tests)) for i, test := range tests { script, err := MultiSigScript(test.keys, test.nrequired) - if err != test.err { - t.Errorf("MultiSigScript #%d unexpected error - "+ - "got %v, want %v", i, err, test.err) + if e := tstCheckScriptError(err, test.err); e != nil { + t.Errorf("MultiSigScript #%d: %v", i, e) continue } @@ -741,14 +735,14 @@ func TestCalcMultiSigStats(t *testing.T) { name: "short script", script: "0x046708afdb0fe5548271967f1a67130b7105cd6a828" + "e03909a67962e0ea1f61d", - err: ErrStackShortScript, + err: scriptError(ErrMalformedPush, ""), }, { name: "stack underflow", script: "RETURN DATA_41 0x046708afdb0fe5548271967f1a" + "67130b7105cd6a828e03909a67962e0ea1f61deb649f6" + "bc3f4cef308", - err: ErrStackUnderflow, + err: scriptError(ErrNotMultisigScript, ""), }, { name: "multisig script", @@ -764,10 +758,11 @@ func TestCalcMultiSigStats(t *testing.T) { for i, test := range tests { script := mustParseShortForm(test.script) - if _, _, err := CalcMultiSigStats(script); err != test.err { - t.Errorf("CalcMultiSigStats #%d (%s) unexpected "+ - "error\ngot: %v\nwant: %v", i, test.name, err, - test.err) + _, _, err := CalcMultiSigStats(script) + if e := tstCheckScriptError(err, test.err); e != nil { + t.Errorf("CalcMultiSigStats #%d (%s): %v", i, test.name, + e) + continue } } } @@ -954,7 +949,7 @@ func TestScriptClass(t *testing.T) { if class != test.class { t.Errorf("%s: expected %s got %s (script %x)", test.name, test.class, class, script) - return + continue } } } @@ -1086,17 +1081,18 @@ func TestGenerateProvablyPruneableOut(t *testing.T) { "4a4b4c4d4e4f202122232425262728292a2b2c2d2e2f303132333435363738393" + "a3b3c3d3e3f3f"), expected: nil, - err: ErrStackLongScript, + err: scriptError(ErrTooMuchNullData, ""), class: NonStandardTy, }, } for i, test := range tests { script, err := GenerateProvablyPruneableOut(test.data) - if err != test.err { - t.Errorf("GenerateProvablyPruneableOut: #%d (%s) unexpected error: "+ - "got %v, want %v", i, test.name, err, test.err) + if e := tstCheckScriptError(err, test.err); e != nil { + t.Errorf("GenerateProvablyPruneableOut: #%d (%s) %v: ", + i, test.name, e) continue + } // Check that the expected result was returned.