diff --git a/LICENSE b/LICENSE index 684c6004..53ba0c56 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ ISC License -Copyright (c) 2013-2016 The btcsuite developers +Copyright (c) 2013-2017 The btcsuite developers Copyright (c) 2015-2016 The Decred developers Permission to use, copy, modify, and distribute this software for any diff --git a/txscript/doc.go b/txscript/doc.go index 2f2b1ec6..7da52161 100644 --- a/txscript/doc.go +++ b/txscript/doc.go @@ -1,4 +1,4 @@ -// Copyright (c) 2013-2015 The btcsuite developers +// Copyright (c) 2013-2017 The btcsuite developers // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. @@ -32,8 +32,11 @@ what conditions must be met in order to spend bitcoins. 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 6c54ea9d..09b4dcfb 100644 --- a/txscript/engine.go +++ b/txscript/engine.go @@ -1,4 +1,4 @@ -// Copyright (c) 2013-2016 The btcsuite developers +// Copyright (c) 2013-2017 The btcsuite developers // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. @@ -72,12 +72,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 = 1000 + MaxStackSize = 1000 - // maxScriptSize is the maximum allowed length of a raw script. - maxScriptSize = 10000 + // MaxScriptSize is the maximum allowed length of a raw script. + MaxScriptSize = 10000 ) // halforder is used to tame ECDSA malleability (see BIP0062). @@ -123,23 +123,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 @@ -174,13 +182,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 } @@ -210,7 +220,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 @@ -227,14 +239,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() @@ -249,7 +265,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 } @@ -278,8 +295,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. @@ -287,7 +307,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. @@ -382,7 +403,8 @@ 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 } @@ -402,7 +424,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 @@ -438,8 +460,9 @@ func (vm *Engine) checkSignatureEncoding(sig []byte) error { // 0x30 + <1-byte> + 0x02 + 0x01 + + 0x2 + 0x01 + if len(sig) < 8 { // Too short - return fmt.Errorf("malformed signature: too short: %d < 8", + str := fmt.Sprintf("malformed signature: too short: %d < 8", len(sig)) + return scriptError(ErrSigDER, str) } // Maximum length is when both numbers are 33 bytes each. It is 33 @@ -448,25 +471,29 @@ func (vm *Engine) checkSignatureEncoding(sig []byte) error { // 0x30 + <1-byte> + 0x02 + 0x21 + <33 bytes> + 0x2 + 0x21 + <33 bytes> if len(sig) > 72 { // Too long - return fmt.Errorf("malformed signature: too long: %d > 72", + str := fmt.Sprintf("malformed signature: too long: %d > 72", len(sig)) + return scriptError(ErrSigDER, str) } if sig[0] != 0x30 { // Wrong type - return fmt.Errorf("malformed signature: format has wrong type: 0x%x", - sig[0]) + str := fmt.Sprintf("malformed signature: format has wrong "+ + "type: 0x%x", sig[0]) + return scriptError(ErrSigDER, str) } if int(sig[1]) != len(sig)-2 { // Invalid length - return fmt.Errorf("malformed signature: bad length: %d != %d", + str := fmt.Sprintf("malformed signature: bad length: %d != %d", sig[1], len(sig)-2) + return scriptError(ErrSigDER, str) } rLen := int(sig[3]) // Make sure S is inside the signature. if rLen+5 > len(sig) { - return fmt.Errorf("malformed signature: S out of bounds") + return scriptError(ErrSigDER, + "malformed signature: S out of bounds") } sLen := int(sig[rLen+5]) @@ -474,49 +501,58 @@ func (vm *Engine) checkSignatureEncoding(sig []byte) error { // The length of the elements does not match the length of the // signature. if rLen+sLen+6 != len(sig) { - return fmt.Errorf("malformed signature: invalid R length") + return scriptError(ErrSigDER, + "malformed signature: invalid R length") } // R elements must be integers. if sig[2] != 0x02 { - return fmt.Errorf("malformed signature: missing first integer marker") + return scriptError(ErrSigDER, + "malformed signature: missing first integer marker") } // Zero-length integers are not allowed for R. if rLen == 0 { - return fmt.Errorf("malformed signature: R length is zero") + return scriptError(ErrSigDER, + "malformed signature: R length is zero") } // R must not be negative. if sig[4]&0x80 != 0 { - return fmt.Errorf("malformed signature: R value is negative") + return scriptError(ErrSigDER, + "malformed signature: R value is negative") } // Null bytes at the start of R are not allowed, unless R would // otherwise be interpreted as a negative number. if rLen > 1 && sig[4] == 0x00 && sig[5]&0x80 == 0 { - return fmt.Errorf("malformed signature: invalid R value") + return scriptError(ErrSigDER, + "malformed signature: invalid R value") } // S elements must be integers. if sig[rLen+4] != 0x02 { - return fmt.Errorf("malformed signature: missing second integer marker") + return scriptError(ErrSigDER, + "malformed signature: missing second integer marker") } // Zero-length integers are not allowed for S. if sLen == 0 { - return fmt.Errorf("malformed signature: S length is zero") + return scriptError(ErrSigDER, + "malformed signature: S length is zero") } // S must not be negative. if sig[rLen+6]&0x80 != 0 { - return fmt.Errorf("malformed signature: S value is negative") + return scriptError(ErrSigDER, + "malformed signature: S value is negative") } // Null bytes at the start of S are not allowed, unless S would // otherwise be interpreted as a negative number. if sLen > 1 && sig[rLen+6] == 0x00 && sig[rLen+7]&0x80 == 0 { - return fmt.Errorf("malformed signature: invalid S value") + return scriptError(ErrSigDER, + "malformed signature: invalid S value") } // Verify the S value is <= half the order of the curve. This check is @@ -529,7 +565,9 @@ func (vm *Engine) checkSignatureEncoding(sig []byte) error { if vm.hasFlag(ScriptVerifyLowS) { sValue := new(big.Int).SetBytes(sig[rLen+6 : rLen+6+sLen]) if sValue.Cmp(halfOrder) > 0 { - return ErrStackInvalidLowSSignature + return scriptError(ErrSigHighS, + "signature is not canonical due to "+ + "unnecessarily high S value") } } @@ -587,10 +625,21 @@ func (vm *Engine) SetAltStack(data [][]byte) { func NewEngine(scriptPubKey []byte, tx *wire.MsgTx, txIdx int, flags ScriptFlags, 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. // @@ -601,13 +650,15 @@ func NewEngine(scriptPubKey []byte, tx *wire.MsgTx, txIdx int, flags ScriptFlags // it should be. vm := Engine{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") } // The engine stores the scripts in parsed form using a slice. This @@ -617,8 +668,10 @@ func NewEngine(scriptPubKey []byte, tx *wire.MsgTx, txIdx int, flags ScriptFlags 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) @@ -637,7 +690,8 @@ func NewEngine(scriptPubKey []byte, tx *wire.MsgTx, txIdx int, flags ScriptFlags if vm.hasFlag(ScriptBip16) && isScriptHash(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 78b47324..c7266b68 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 // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. @@ -119,29 +119,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) @@ -193,7 +188,7 @@ func TestInvalidFlagCombinations(t *testing.T) { for i, test := range tests { _, err := NewEngine(pkScript, tx, 0, test, 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 ee908c72..64bed9df 100644 --- a/txscript/error.go +++ b/txscript/error.go @@ -1,154 +1,313 @@ -// Copyright (c) 2013-2015 The btcsuite developers +// Copyright (c) 2013-2017 The btcsuite developers // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. package txscript import ( - "errors" "fmt" ) -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 ScriptVerifyLowS - // flag is set and 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") -) - -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 // ErrUnsupportedAddress is returned when a concrete type that // implements a btcutil.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 + + // ErrTooManyRequiredSigs is returned from MultiSigScript when the + // specified number of required signatures is larger than the number of + // provided public keys. + ErrTooManyRequiredSigs + + // ErrTooMuchNullData is returned from NullDataScript when the length of + // the provided data exceeds MaxDataCarrierSize. + ErrTooMuchNullData + + // ------------------------------------------ + // Failures related to final execution state. + // ------------------------------------------ + + // ErrEarlyReturn is returned when OP_RETURN is executed in the script. + ErrEarlyReturn + + // ErrEmptyStack is returned when the script evaluated without error, + // but terminated with an empty top stack element. + ErrEmptyStack + + // ErrEvalFalse is returned when the script evaluated without error but + // terminated with a false top stack element. + ErrEvalFalse + + // ErrScriptUnfinished is returned when CheckErrorCondition is called on + // a script that has not finished executing. + ErrScriptUnfinished + + // 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 + + // ErrNumberTooBig 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. + ErrNumberTooBig + + // -------------------------------------------- + // 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. + // -------------------------------------------- + + // 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 + + // --------------------------------- + // 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 + + // ErrSigDER is returned when a signature is not a canonically-encoded + // DER signature. + ErrSigDER + + // ErrSigHighS is returned when the ScriptVerifyLowS flag is set and the + // script contains any signatures whose S values are higher than the + // 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 + + // ErrSigNullDummy is returned when the ScriptStrictMultiSig flag is set + // and a multisig script has anything other than 0 for the extra dummy + // argument. + ErrSigNullDummy + + // 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", + ErrUnsupportedAddress: "ErrUnsupportedAddress", + ErrNotMultisigScript: "ErrNotMultisigScript", + ErrTooManyRequiredSigs: "ErrTooManyRequiredSigs", + ErrTooMuchNullData: "ErrTooMuchNullData", + ErrEarlyReturn: "ErrEarlyReturn", + ErrEmptyStack: "ErrEmptyStack", + ErrEvalFalse: "ErrEvalFalse", + ErrScriptUnfinished: "ErrScriptUnfinished", + ErrInvalidProgramCounter: "ErrInvalidProgramCounter", + ErrScriptTooBig: "ErrScriptTooBig", + ErrElementTooBig: "ErrElementTooBig", + ErrTooManyOperations: "ErrTooManyOperations", + ErrStackOverflow: "ErrStackOverflow", + ErrInvalidPubKeyCount: "ErrInvalidPubKeyCount", + ErrInvalidSignatureCount: "ErrInvalidSignatureCount", + ErrNumberTooBig: "ErrNumberTooBig", + ErrVerify: "ErrVerify", + ErrEqualVerify: "ErrEqualVerify", + ErrNumEqualVerify: "ErrNumEqualVerify", + ErrCheckSigVerify: "ErrCheckSigVerify", + ErrCheckMultiSigVerify: "ErrCheckMultiSigVerify", + ErrDisabledOpcode: "ErrDisabledOpcode", + ErrReservedOpcode: "ErrReservedOpcode", + ErrMalformedPush: "ErrMalformedPush", + ErrInvalidStackOperation: "ErrInvalidStackOperation", + ErrUnbalancedConditional: "ErrUnbalancedConditional", + ErrMinimalData: "ErrMinimalData", + ErrInvalidSigHashType: "ErrInvalidSigHashType", + ErrSigDER: "ErrSigDER", + ErrSigHighS: "ErrSigHighS", + ErrNotPushOnly: "ErrNotPushOnly", + ErrSigNullDummy: "ErrSigNullDummy", + 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 +} diff --git a/txscript/error_test.go b/txscript/error_test.go new file mode 100644 index 00000000..ce8d09c5 --- /dev/null +++ b/txscript/error_test.go @@ -0,0 +1,106 @@ +// 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"}, + {ErrUnsupportedAddress, "ErrUnsupportedAddress"}, + {ErrTooManyRequiredSigs, "ErrTooManyRequiredSigs"}, + {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"}, + {ErrNumberTooBig, "ErrNumberTooBig"}, + {ErrVerify, "ErrVerify"}, + {ErrEqualVerify, "ErrEqualVerify"}, + {ErrNumEqualVerify, "ErrNumEqualVerify"}, + {ErrCheckSigVerify, "ErrCheckSigVerify"}, + {ErrCheckMultiSigVerify, "ErrCheckMultiSigVerify"}, + {ErrDisabledOpcode, "ErrDisabledOpcode"}, + {ErrReservedOpcode, "ErrReservedOpcode"}, + {ErrMalformedPush, "ErrMalformedPush"}, + {ErrInvalidStackOperation, "ErrInvalidStackOperation"}, + {ErrUnbalancedConditional, "ErrUnbalancedConditional"}, + {ErrMinimalData, "ErrMinimalData"}, + {ErrInvalidSigHashType, "ErrInvalidSigHashType"}, + {ErrSigDER, "ErrSigDER"}, + {ErrSigHighS, "ErrSigHighS"}, + {ErrNotPushOnly, "ErrNotPushOnly"}, + {ErrSigNullDummy, "ErrSigNullDummy"}, + {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 + } + } +} diff --git a/txscript/opcode.go b/txscript/opcode.go index 3e7a2495..54392bba 100644 --- a/txscript/opcode.go +++ b/txscript/opcode.go @@ -9,7 +9,6 @@ import ( "crypto/sha1" "crypto/sha256" "encoding/binary" - "errors" "fmt" "hash" @@ -698,28 +697,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 @@ -780,7 +796,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 } @@ -809,7 +829,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 @@ -826,19 +849,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 @@ -880,8 +909,9 @@ func opcodeNop(op *parsedOpcode, vm *Engine) error { case OP_NOP1, OP_NOP4, OP_NOP5, OP_NOP6, OP_NOP7, OP_NOP8, OP_NOP9, OP_NOP10: if vm.hasFlag(ScriptDiscourageUpgradableNops) { - return fmt.Errorf("OP_NOP%d reserved for soft-fork "+ + str := fmt.Sprintf("OP_NOP%d reserved for soft-fork "+ "upgrades", op.opcode.value-(OP_NOP1-1)) + return scriptError(ErrDiscourageUpgradableNOPs, str) } } return nil @@ -959,7 +989,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 @@ -983,31 +1015,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. @@ -1016,14 +1060,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 @@ -1039,8 +1085,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 } @@ -1067,7 +1113,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 @@ -1095,7 +1142,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 @@ -1111,8 +1159,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 } @@ -1139,7 +1187,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) @@ -1154,8 +1203,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 @@ -1164,8 +1214,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. @@ -1399,7 +1450,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 } @@ -1637,7 +1688,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 } @@ -2045,7 +2096,7 @@ func opcodeCheckSig(op *parsedOpcode, vm *Engine) error { 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 } @@ -2085,12 +2136,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) @@ -2108,12 +2168,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) @@ -2139,8 +2202,9 @@ func opcodeCheckMultiSig(op *parsedOpcode, vm *Engine) error { // value which unfortunately provides a source of malleability. Thus, // there is a script flag to force an error when the value is NOT 0. if vm.hasFlag(ScriptStrictMultiSig) && len(dummy) != 0 { - return fmt.Errorf("multisig dummy argument is not zero length: %d", - len(dummy)) + str := fmt.Sprintf("multisig dummy argument has length %d "+ + "instead of 0", len(dummy)) + return scriptError(ErrSigNullDummy, str) } // Get script starting from the most recent OP_CODESEPARATOR. @@ -2267,7 +2331,7 @@ func opcodeCheckMultiSig(op *parsedOpcode, vm *Engine) error { 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 969ce674..6e3205a2 100644 --- a/txscript/opcode_test.go +++ b/txscript/opcode_test.go @@ -1,4 +1,4 @@ -// Copyright (c) 2013-2016 The btcsuite developers +// Copyright (c) 2013-2017 The btcsuite developers // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. @@ -24,10 +24,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/script.go b/txscript/script.go index 4397f774..b7da905f 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 // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. @@ -120,7 +120,11 @@ func parseScriptTemplate(script []byte, opcodes *[256]opcode) ([]parsedOpcode, e // 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. @@ -133,7 +137,11 @@ func parseScriptTemplate(script []byte, opcodes *[256]opcode) ([]parsedOpcode, e 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. @@ -149,9 +157,10 @@ func parseScriptTemplate(script []byte, opcodes *[256]opcode) ([]parsedOpcode, e (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. @@ -160,7 +169,11 @@ func parseScriptTemplate(script []byte, opcodes *[256]opcode) ([]parsedOpcode, e // 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 d309d39a..1ffd0711 100644 --- a/txscript/script_test.go +++ b/txscript/script_test.go @@ -1,4 +1,4 @@ -// Copyright (c) 2013-2016 The btcsuite developers +// Copyright (c) 2013-2017 The btcsuite developers // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. @@ -48,7 +48,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_FALSE], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_1 short", @@ -56,7 +56,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_1], data: nil, }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_1", @@ -72,7 +72,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", @@ -80,7 +80,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_2], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_2", @@ -96,7 +96,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", @@ -104,7 +104,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_3], data: make([]byte, 2), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_3", @@ -120,7 +120,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", @@ -128,7 +128,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_4], data: make([]byte, 3), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_4", @@ -144,7 +144,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", @@ -152,7 +152,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_5], data: make([]byte, 4), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_5", @@ -168,7 +168,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", @@ -176,7 +176,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_6], data: make([]byte, 5), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_6", @@ -192,7 +192,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", @@ -200,7 +200,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_7], data: make([]byte, 6), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_7", @@ -216,7 +216,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", @@ -224,7 +224,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_8], data: make([]byte, 7), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_8", @@ -240,7 +240,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", @@ -248,7 +248,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_9], data: make([]byte, 8), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_9", @@ -264,7 +264,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", @@ -272,7 +272,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_10], data: make([]byte, 9), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_10", @@ -288,7 +288,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", @@ -296,7 +296,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_11], data: make([]byte, 10), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_11", @@ -312,7 +312,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", @@ -320,7 +320,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_12], data: make([]byte, 11), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_12", @@ -336,7 +336,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", @@ -344,7 +344,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_13], data: make([]byte, 12), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_13", @@ -360,7 +360,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", @@ -368,7 +368,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_14], data: make([]byte, 13), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_14", @@ -384,7 +384,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", @@ -392,7 +392,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_15], data: make([]byte, 14), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_15", @@ -408,7 +408,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", @@ -416,7 +416,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_16], data: make([]byte, 15), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_16", @@ -432,7 +432,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", @@ -440,7 +440,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_17], data: make([]byte, 16), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_17", @@ -456,7 +456,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", @@ -464,7 +464,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_18], data: make([]byte, 17), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_18", @@ -480,7 +480,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", @@ -488,7 +488,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_19], data: make([]byte, 18), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_19", @@ -504,7 +504,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", @@ -512,7 +512,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_20], data: make([]byte, 19), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_20", @@ -528,7 +528,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", @@ -536,7 +536,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_21], data: make([]byte, 20), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_21", @@ -552,7 +552,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", @@ -560,7 +560,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_22], data: make([]byte, 21), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_22", @@ -576,7 +576,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", @@ -584,7 +584,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_23], data: make([]byte, 22), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_23", @@ -600,7 +600,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", @@ -608,7 +608,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_24], data: make([]byte, 23), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_24", @@ -624,7 +624,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", @@ -632,7 +632,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_25], data: make([]byte, 24), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_25", @@ -648,7 +648,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", @@ -656,7 +656,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_26], data: make([]byte, 25), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_26", @@ -672,7 +672,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", @@ -680,7 +680,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_27], data: make([]byte, 26), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_27", @@ -696,7 +696,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", @@ -704,7 +704,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_28], data: make([]byte, 27), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_28", @@ -720,7 +720,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", @@ -728,7 +728,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_29], data: make([]byte, 28), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_29", @@ -744,7 +744,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", @@ -752,7 +752,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_30], data: make([]byte, 29), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_30", @@ -768,7 +768,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", @@ -776,7 +776,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_31], data: make([]byte, 30), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_31", @@ -792,7 +792,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", @@ -800,7 +800,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_32], data: make([]byte, 31), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_32", @@ -816,7 +816,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", @@ -824,7 +824,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_33], data: make([]byte, 32), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_33", @@ -840,7 +840,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", @@ -848,7 +848,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_34], data: make([]byte, 33), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_34", @@ -864,7 +864,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", @@ -872,7 +872,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_35], data: make([]byte, 34), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_35", @@ -888,7 +888,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", @@ -896,7 +896,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_36], data: make([]byte, 35), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_36", @@ -912,7 +912,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", @@ -920,7 +920,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_37], data: make([]byte, 36), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_37", @@ -936,7 +936,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", @@ -944,7 +944,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_38], data: make([]byte, 37), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_38", @@ -960,7 +960,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", @@ -968,7 +968,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_39], data: make([]byte, 38), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_39", @@ -984,7 +984,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", @@ -992,7 +992,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_40], data: make([]byte, 39), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_40", @@ -1008,7 +1008,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", @@ -1016,7 +1016,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_41], data: make([]byte, 40), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_41", @@ -1032,7 +1032,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", @@ -1040,7 +1040,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_42], data: make([]byte, 41), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_42", @@ -1056,7 +1056,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", @@ -1064,7 +1064,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_43], data: make([]byte, 42), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_43", @@ -1080,7 +1080,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", @@ -1088,7 +1088,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_44], data: make([]byte, 43), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_44", @@ -1104,7 +1104,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", @@ -1112,7 +1112,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_45], data: make([]byte, 44), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_45", @@ -1128,7 +1128,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", @@ -1136,7 +1136,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_46], data: make([]byte, 45), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_46", @@ -1152,7 +1152,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", @@ -1160,7 +1160,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_47], data: make([]byte, 46), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_47", @@ -1176,7 +1176,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", @@ -1184,7 +1184,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_48], data: make([]byte, 47), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_48", @@ -1200,7 +1200,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", @@ -1208,7 +1208,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_49], data: make([]byte, 48), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_49", @@ -1224,7 +1224,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", @@ -1232,7 +1232,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_50], data: make([]byte, 49), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_50", @@ -1248,7 +1248,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", @@ -1256,7 +1256,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_51], data: make([]byte, 50), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_51", @@ -1272,7 +1272,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", @@ -1280,7 +1280,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_52], data: make([]byte, 51), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_52", @@ -1296,7 +1296,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", @@ -1304,7 +1304,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_53], data: make([]byte, 52), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_53", @@ -1320,7 +1320,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", @@ -1328,7 +1328,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_54], data: make([]byte, 53), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_54", @@ -1344,7 +1344,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", @@ -1352,7 +1352,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_55], data: make([]byte, 54), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_55", @@ -1368,7 +1368,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", @@ -1376,7 +1376,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_56], data: make([]byte, 55), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_56", @@ -1392,7 +1392,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", @@ -1400,7 +1400,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_57], data: make([]byte, 56), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_57", @@ -1416,7 +1416,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", @@ -1424,7 +1424,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_58], data: make([]byte, 57), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_58", @@ -1440,7 +1440,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", @@ -1448,7 +1448,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_59], data: make([]byte, 58), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_59", @@ -1464,7 +1464,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", @@ -1472,7 +1472,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_60], data: make([]byte, 59), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_60", @@ -1488,7 +1488,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", @@ -1496,7 +1496,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_61], data: make([]byte, 60), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_61", @@ -1512,7 +1512,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", @@ -1520,7 +1520,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_62], data: make([]byte, 61), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_62", @@ -1536,7 +1536,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", @@ -1544,7 +1544,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_63], data: make([]byte, 62), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_63", @@ -1560,7 +1560,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", @@ -1568,7 +1568,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_64], data: make([]byte, 63), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_64", @@ -1584,7 +1584,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", @@ -1592,7 +1592,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_65], data: make([]byte, 64), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_65", @@ -1608,7 +1608,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", @@ -1616,7 +1616,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_66], data: make([]byte, 65), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_66", @@ -1632,7 +1632,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", @@ -1640,7 +1640,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_67], data: make([]byte, 66), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_67", @@ -1656,7 +1656,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", @@ -1664,7 +1664,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_68], data: make([]byte, 67), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_68", @@ -1680,7 +1680,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", @@ -1688,7 +1688,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_69], data: make([]byte, 68), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_69", @@ -1704,7 +1704,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", @@ -1712,7 +1712,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_70], data: make([]byte, 69), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_70", @@ -1728,7 +1728,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", @@ -1736,7 +1736,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_71], data: make([]byte, 70), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_71", @@ -1752,7 +1752,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", @@ -1760,7 +1760,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_72], data: make([]byte, 71), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_72", @@ -1776,7 +1776,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", @@ -1784,7 +1784,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_73], data: make([]byte, 72), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_73", @@ -1800,7 +1800,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", @@ -1808,7 +1808,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_74], data: make([]byte, 73), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_74", @@ -1824,7 +1824,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", @@ -1832,7 +1832,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_75], data: make([]byte, 74), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DATA_75", @@ -1848,7 +1848,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DATA_75], data: make([]byte, 76), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_PUSHDATA1", @@ -1888,7 +1888,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_1NEGATE], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_RESERVED", @@ -1904,7 +1904,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_RESERVED], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_TRUE", @@ -1920,7 +1920,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_TRUE], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_2", @@ -1936,7 +1936,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_2], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_2", @@ -1952,7 +1952,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_2], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_3", @@ -1968,7 +1968,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_3], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_4", @@ -1984,7 +1984,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_4], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_5", @@ -2000,7 +2000,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_5], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_6", @@ -2016,7 +2016,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_6], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_7", @@ -2032,7 +2032,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_7], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_8", @@ -2048,7 +2048,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_8], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_9", @@ -2064,7 +2064,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_9], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_10", @@ -2080,7 +2080,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_10], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_11", @@ -2096,7 +2096,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_11], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_12", @@ -2112,7 +2112,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_12], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_13", @@ -2128,7 +2128,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_13], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_14", @@ -2144,7 +2144,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_14], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_15", @@ -2160,7 +2160,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_15], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_16", @@ -2176,7 +2176,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_16], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_NOP", @@ -2192,7 +2192,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_NOP], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_VER", @@ -2208,7 +2208,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_VER], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_IF", @@ -2224,7 +2224,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_IF], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_NOTIF", @@ -2240,7 +2240,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_NOTIF], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_VERIF", @@ -2256,7 +2256,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_VERIF], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_VERNOTIF", @@ -2272,7 +2272,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_VERNOTIF], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_ELSE", @@ -2288,7 +2288,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_ELSE], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_ENDIF", @@ -2304,7 +2304,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_ENDIF], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_VERIFY", @@ -2320,7 +2320,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_VERIFY], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_RETURN", @@ -2336,7 +2336,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_RETURN], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_TOALTSTACK", @@ -2352,7 +2352,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_TOALTSTACK], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_FROMALTSTACK", @@ -2368,7 +2368,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_FROMALTSTACK], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_2DROP", @@ -2384,7 +2384,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_2DROP], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_2DUP", @@ -2400,7 +2400,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_2DUP], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_3DUP", @@ -2416,7 +2416,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_3DUP], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_2OVER", @@ -2432,7 +2432,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_2OVER], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_2ROT", @@ -2448,7 +2448,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_2ROT], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_2SWAP", @@ -2464,7 +2464,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_2SWAP], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_IFDUP", @@ -2480,7 +2480,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_IFDUP], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DEPTH", @@ -2496,7 +2496,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DEPTH], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DROP", @@ -2512,7 +2512,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DROP], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DUP", @@ -2528,7 +2528,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DUP], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_NIP", @@ -2544,7 +2544,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_NIP], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_OVER", @@ -2560,7 +2560,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_OVER], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_PICK", @@ -2576,7 +2576,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_PICK], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_ROLL", @@ -2592,7 +2592,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_ROLL], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_ROT", @@ -2608,7 +2608,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_ROT], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_SWAP", @@ -2624,7 +2624,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_SWAP], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_TUCK", @@ -2640,7 +2640,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_TUCK], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_CAT", @@ -2656,7 +2656,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_CAT], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_SUBSTR", @@ -2672,7 +2672,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_SUBSTR], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_LEFT", @@ -2688,7 +2688,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_LEFT], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_LEFT", @@ -2704,7 +2704,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_LEFT], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_RIGHT", @@ -2720,7 +2720,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_RIGHT], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_SIZE", @@ -2736,7 +2736,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_SIZE], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_INVERT", @@ -2752,7 +2752,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_INVERT], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_AND", @@ -2768,7 +2768,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_AND], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_OR", @@ -2784,7 +2784,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_OR], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_XOR", @@ -2800,7 +2800,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_XOR], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_EQUAL", @@ -2816,7 +2816,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_EQUAL], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_EQUALVERIFY", @@ -2832,7 +2832,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_EQUALVERIFY], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_RESERVED1", @@ -2848,7 +2848,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_RESERVED1], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_RESERVED2", @@ -2864,7 +2864,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_RESERVED2], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_1ADD", @@ -2880,7 +2880,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_1ADD], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_1SUB", @@ -2896,7 +2896,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_1SUB], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_2MUL", @@ -2912,7 +2912,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_2MUL], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_2DIV", @@ -2928,7 +2928,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_2DIV], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_NEGATE", @@ -2944,7 +2944,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_NEGATE], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_ABS", @@ -2960,7 +2960,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_ABS], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_NOT", @@ -2976,7 +2976,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_NOT], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_0NOTEQUAL", @@ -2992,7 +2992,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_0NOTEQUAL], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_ADD", @@ -3008,7 +3008,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_ADD], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_SUB", @@ -3024,7 +3024,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_SUB], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_MUL", @@ -3040,7 +3040,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_MUL], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_DIV", @@ -3056,7 +3056,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_DIV], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_MOD", @@ -3072,7 +3072,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_MOD], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_LSHIFT", @@ -3088,7 +3088,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_LSHIFT], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_RSHIFT", @@ -3104,7 +3104,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_RSHIFT], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_BOOLAND", @@ -3120,7 +3120,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_BOOLAND], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_BOOLOR", @@ -3136,7 +3136,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_BOOLOR], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_NUMEQUAL", @@ -3152,7 +3152,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_NUMEQUAL], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_NUMEQUALVERIFY", @@ -3168,7 +3168,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_NUMEQUALVERIFY], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_NUMNOTEQUAL", @@ -3184,7 +3184,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_NUMNOTEQUAL], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_LESSTHAN", @@ -3200,7 +3200,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_LESSTHAN], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_GREATERTHAN", @@ -3216,7 +3216,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_GREATERTHAN], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_LESSTHANOREQUAL", @@ -3232,7 +3232,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_LESSTHANOREQUAL], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_GREATERTHANOREQUAL", @@ -3248,7 +3248,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_GREATERTHANOREQUAL], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_MIN", @@ -3264,7 +3264,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_MIN], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_MAX", @@ -3280,7 +3280,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_MAX], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_WITHIN", @@ -3296,7 +3296,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_WITHIN], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_RIPEMD160", @@ -3312,7 +3312,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_RIPEMD160], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_SHA1", @@ -3328,7 +3328,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_SHA1], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_SHA256", @@ -3344,7 +3344,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_SHA256], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_HASH160", @@ -3360,7 +3360,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_HASH160], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_HASH256", @@ -3376,7 +3376,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_HASH256], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_CODESAPERATOR", @@ -3392,7 +3392,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_CODESEPARATOR], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_CHECKSIG", @@ -3408,7 +3408,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_CHECKSIG], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_CHECKSIGVERIFY", @@ -3424,7 +3424,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_CHECKSIGVERIFY], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_CHECKMULTISIG", @@ -3440,7 +3440,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_CHECKMULTISIG], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_CHECKMULTISIGVERIFY", @@ -3456,7 +3456,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_CHECKMULTISIGVERIFY], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_NOP1", @@ -3472,7 +3472,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_NOP1], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_NOP2", @@ -3488,7 +3488,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_NOP2], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_NOP3", @@ -3504,7 +3504,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_NOP3], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_NOP4", @@ -3520,7 +3520,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_NOP4], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_NOP5", @@ -3536,7 +3536,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_NOP5], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_NOP6", @@ -3552,7 +3552,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_NOP6], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_NOP7", @@ -3568,7 +3568,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_NOP7], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_NOP8", @@ -3584,7 +3584,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_NOP8], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_NOP9", @@ -3600,7 +3600,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_NOP9], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_NOP10", @@ -3616,7 +3616,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_NOP10], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_PUBKEYHASH", @@ -3632,7 +3632,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_PUBKEYHASH], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_PUBKEY", @@ -3648,7 +3648,7 @@ func TestUnparsingInvalidOpcodes(t *testing.T) { opcode: &opcodeArray[OP_PUBKEY], data: make([]byte, 1), }, - expectedErr: ErrStackInvalidOpcode, + expectedErr: scriptError(ErrInternal, ""), }, { name: "OP_INVALIDOPCODE", @@ -3664,15 +3664,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 } } } @@ -3802,12 +3802,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", @@ -3828,7 +3826,6 @@ func TestGetPreciseSigOps(t *testing.T) { { name: "pushed script doesn't parse", scriptSig: mustParseShortForm("DATA_2 PUSHDATA1 0x02"), - err: ErrStackShortScript, }, } @@ -3891,13 +3888,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, ""), }, } @@ -3917,20 +3914,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) } } } @@ -4048,13 +4039,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, ""), }, } @@ -4072,20 +4063,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 f2f2dc07..7984dd96 100644 --- a/txscript/scriptbuilder.go +++ b/txscript/scriptbuilder.go @@ -62,9 +62,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 } @@ -83,9 +83,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 } @@ -198,10 +198,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 } @@ -212,7 +212,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 } @@ -230,10 +230,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 7e316c69..89f2b861 100644 --- a/txscript/scriptbuilder_test.go +++ b/txscript/scriptbuilder_test.go @@ -291,7 +291,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) @@ -311,7 +311,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 - "+ @@ -324,7 +324,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 - "+ @@ -345,7 +345,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 9d11ea21..a89d5f39 100644 --- a/txscript/scriptnum.go +++ b/txscript/scriptnum.go @@ -1,9 +1,13 @@ -// Copyright (c) 2015 The btcsuite developers +// Copyright (c) 2015-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 ( + "fmt" +) + const ( maxInt32 = 1<<31 - 1 minInt32 = -1 << 31 @@ -61,7 +65,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) } } @@ -180,7 +186,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(ErrNumberTooBig, str) } // Enforce minimal encoded if requested. diff --git a/txscript/scriptnum_test.go b/txscript/scriptnum_test.go index ee7cab56..e32862b7 100644 --- a/txscript/scriptnum_test.go +++ b/txscript/scriptnum_test.go @@ -1,4 +1,4 @@ -// Copyright (c) 2015 The btcsuite developers +// Copyright (c) 2015-2017 The btcsuite developers // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. @@ -91,6 +91,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. + errNumTooBig := scriptError(ErrNumberTooBig, "") + errMinimalData := scriptError(ErrMinimalData, "") + tests := []struct { serialized []byte num scriptNum @@ -99,7 +104,7 @@ func TestMakeScriptNum(t *testing.T) { err error }{ // Minimal encoding must reject negative 0. - {hexToBytes("80"), 0, defaultScriptNumLen, true, ErrStackMinimalData}, + {hexToBytes("80"), 0, defaultScriptNumLen, true, errMinimalData}, // Minimally encoded valid values with minimal encoding flag. // Should not error and return expected integral number. @@ -140,35 +145,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, defaultScriptNumLen, true, ErrStackNumberTooBig}, - {hexToBytes("0000008080"), 0, defaultScriptNumLen, true, ErrStackNumberTooBig}, - {hexToBytes("0000009000"), 0, defaultScriptNumLen, true, ErrStackNumberTooBig}, - {hexToBytes("0000009080"), 0, defaultScriptNumLen, true, ErrStackNumberTooBig}, - {hexToBytes("ffffffff00"), 0, defaultScriptNumLen, true, ErrStackNumberTooBig}, - {hexToBytes("ffffffff80"), 0, defaultScriptNumLen, true, ErrStackNumberTooBig}, - {hexToBytes("0000000001"), 0, defaultScriptNumLen, true, ErrStackNumberTooBig}, - {hexToBytes("0000000081"), 0, defaultScriptNumLen, true, ErrStackNumberTooBig}, - {hexToBytes("ffffffffffff00"), 0, defaultScriptNumLen, true, ErrStackNumberTooBig}, - {hexToBytes("ffffffffffff80"), 0, defaultScriptNumLen, true, ErrStackNumberTooBig}, - {hexToBytes("ffffffffffffff00"), 0, defaultScriptNumLen, true, ErrStackNumberTooBig}, - {hexToBytes("ffffffffffffff80"), 0, defaultScriptNumLen, true, ErrStackNumberTooBig}, - {hexToBytes("ffffffffffffff7f"), 0, defaultScriptNumLen, true, ErrStackNumberTooBig}, - {hexToBytes("ffffffffffffffff"), 0, defaultScriptNumLen, true, ErrStackNumberTooBig}, + {hexToBytes("0000008000"), 0, defaultScriptNumLen, true, errNumTooBig}, + {hexToBytes("0000008080"), 0, defaultScriptNumLen, true, errNumTooBig}, + {hexToBytes("0000009000"), 0, defaultScriptNumLen, true, errNumTooBig}, + {hexToBytes("0000009080"), 0, defaultScriptNumLen, true, errNumTooBig}, + {hexToBytes("ffffffff00"), 0, defaultScriptNumLen, true, errNumTooBig}, + {hexToBytes("ffffffff80"), 0, defaultScriptNumLen, true, errNumTooBig}, + {hexToBytes("0000000001"), 0, defaultScriptNumLen, true, errNumTooBig}, + {hexToBytes("0000000081"), 0, defaultScriptNumLen, true, errNumTooBig}, + {hexToBytes("ffffffffffff00"), 0, defaultScriptNumLen, true, errNumTooBig}, + {hexToBytes("ffffffffffff80"), 0, defaultScriptNumLen, true, errNumTooBig}, + {hexToBytes("ffffffffffffff00"), 0, defaultScriptNumLen, true, errNumTooBig}, + {hexToBytes("ffffffffffffff80"), 0, defaultScriptNumLen, true, errNumTooBig}, + {hexToBytes("ffffffffffffff7f"), 0, defaultScriptNumLen, true, errNumTooBig}, + {hexToBytes("ffffffffffffffff"), 0, defaultScriptNumLen, true, errNumTooBig}, // Non-minimally encoded, but otherwise valid values with // minimal encoding flag. Should error and return 0. - {hexToBytes("00"), 0, defaultScriptNumLen, true, ErrStackMinimalData}, // 0 - {hexToBytes("0100"), 0, defaultScriptNumLen, true, ErrStackMinimalData}, // 1 - {hexToBytes("7f00"), 0, defaultScriptNumLen, true, ErrStackMinimalData}, // 127 - {hexToBytes("800000"), 0, defaultScriptNumLen, true, ErrStackMinimalData}, // 128 - {hexToBytes("810000"), 0, defaultScriptNumLen, true, ErrStackMinimalData}, // 129 - {hexToBytes("000100"), 0, defaultScriptNumLen, true, ErrStackMinimalData}, // 256 - {hexToBytes("ff7f00"), 0, defaultScriptNumLen, true, ErrStackMinimalData}, // 32767 - {hexToBytes("00800000"), 0, defaultScriptNumLen, true, ErrStackMinimalData}, // 32768 - {hexToBytes("ffff0000"), 0, defaultScriptNumLen, true, ErrStackMinimalData}, // 65535 - {hexToBytes("00000800"), 0, defaultScriptNumLen, true, ErrStackMinimalData}, // 524288 - {hexToBytes("00007000"), 0, defaultScriptNumLen, true, ErrStackMinimalData}, // 7340032 - {hexToBytes("0009000100"), 0, 5, true, ErrStackMinimalData}, // 16779520 + {hexToBytes("00"), 0, defaultScriptNumLen, true, errMinimalData}, // 0 + {hexToBytes("0100"), 0, defaultScriptNumLen, true, errMinimalData}, // 1 + {hexToBytes("7f00"), 0, defaultScriptNumLen, true, errMinimalData}, // 127 + {hexToBytes("800000"), 0, defaultScriptNumLen, true, errMinimalData}, // 128 + {hexToBytes("810000"), 0, defaultScriptNumLen, true, errMinimalData}, // 129 + {hexToBytes("000100"), 0, defaultScriptNumLen, true, errMinimalData}, // 256 + {hexToBytes("ff7f00"), 0, defaultScriptNumLen, true, errMinimalData}, // 32767 + {hexToBytes("00800000"), 0, defaultScriptNumLen, true, errMinimalData}, // 32768 + {hexToBytes("ffff0000"), 0, defaultScriptNumLen, true, errMinimalData}, // 65535 + {hexToBytes("00000800"), 0, defaultScriptNumLen, true, errMinimalData}, // 524288 + {hexToBytes("00007000"), 0, defaultScriptNumLen, 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 @@ -188,18 +193,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/stack.go b/txscript/stack.go index 4e7f541f..cea20462 100644 --- a/txscript/stack.go +++ b/txscript/stack.go @@ -1,10 +1,13 @@ -// Copyright (c) 2013-2015 The btcsuite developers +// Copyright (c) 2013-2017 The btcsuite developers // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. package txscript -import "encoding/hex" +import ( + "encoding/hex" + "fmt" +) // asBool gets the boolean value of the byte array. func asBool(t []byte) bool { @@ -103,7 +106,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 @@ -141,7 +146,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] @@ -197,7 +204,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-- { @@ -216,7 +224,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. @@ -238,7 +247,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 @@ -262,7 +272,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 @@ -285,7 +296,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 80a02b21..9228ecff 100644 --- a/txscript/stack_test.go +++ b/txscript/stack_test.go @@ -1,4 +1,4 @@ -// Copyright (c) 2013-2015 The btcsuite developers +// Copyright (c) 2013-2017 The btcsuite developers // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. @@ -8,19 +8,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", @@ -38,7 +71,7 @@ func TestStack(t *testing.T) { _, err := s.PeekByteArray(5) return err }, - ErrStackUnderflow, + scriptError(ErrInvalidStackOperation, ""), nil, }, { @@ -48,7 +81,7 @@ func TestStack(t *testing.T) { _, err := s.PeekInt(5) return err }, - ErrStackUnderflow, + scriptError(ErrInvalidStackOperation, ""), nil, }, { @@ -58,7 +91,7 @@ func TestStack(t *testing.T) { _, err := s.PeekBool(5) return err }, - ErrStackUnderflow, + scriptError(ErrInvalidStackOperation, ""), nil, }, { @@ -104,7 +137,7 @@ func TestStack(t *testing.T) { } return nil }, - ErrStackUnderflow, + scriptError(ErrInvalidStackOperation, ""), nil, }, { @@ -148,7 +181,7 @@ func TestStack(t *testing.T) { _, err := s.PopBool() return err }, - ErrStackUnderflow, + scriptError(ErrInvalidStackOperation, ""), nil, }, { @@ -370,7 +403,7 @@ func TestStack(t *testing.T) { func(s *stack) error { return s.DupN(0) }, - ErrStackInvalidArgs, + scriptError(ErrInvalidStackOperation, ""), nil, }, { @@ -379,7 +412,7 @@ func TestStack(t *testing.T) { func(s *stack) error { return s.DupN(-1) }, - ErrStackInvalidArgs, + scriptError(ErrInvalidStackOperation, ""), nil, }, { @@ -388,7 +421,7 @@ func TestStack(t *testing.T) { func(s *stack) error { return s.DupN(2) }, - ErrStackUnderflow, + scriptError(ErrInvalidStackOperation, ""), nil, }, { @@ -519,7 +552,7 @@ func TestStack(t *testing.T) { // bite off more than we can chew return s.NipN(3) }, - ErrStackUnderflow, + scriptError(ErrInvalidStackOperation, ""), [][]byte{{2}, {3}}, }, { @@ -537,7 +570,7 @@ func TestStack(t *testing.T) { func(s *stack) error { return s.Tuck() }, - ErrStackUnderflow, + scriptError(ErrInvalidStackOperation, ""), nil, }, { @@ -546,7 +579,7 @@ func TestStack(t *testing.T) { func(s *stack) error { return s.Tuck() }, - ErrStackUnderflow, + scriptError(ErrInvalidStackOperation, ""), nil, }, { @@ -591,7 +624,7 @@ func TestStack(t *testing.T) { func(s *stack) error { return s.DropN(5) }, - ErrStackUnderflow, + scriptError(ErrInvalidStackOperation, ""), nil, }, { @@ -600,7 +633,7 @@ func TestStack(t *testing.T) { func(s *stack) error { return s.DropN(0) }, - ErrStackInvalidArgs, + scriptError(ErrInvalidStackOperation, ""), nil, }, { @@ -627,7 +660,7 @@ func TestStack(t *testing.T) { func(s *stack) error { return s.RotN(1) }, - ErrStackUnderflow, + scriptError(ErrInvalidStackOperation, ""), nil, }, { @@ -636,7 +669,7 @@ func TestStack(t *testing.T) { func(s *stack) error { return s.RotN(0) }, - ErrStackInvalidArgs, + scriptError(ErrInvalidStackOperation, ""), nil, }, { @@ -663,7 +696,7 @@ func TestStack(t *testing.T) { func(s *stack) error { return s.SwapN(1) }, - ErrStackUnderflow, + scriptError(ErrInvalidStackOperation, ""), nil, }, { @@ -672,7 +705,7 @@ func TestStack(t *testing.T) { func(s *stack) error { return s.SwapN(0) }, - ErrStackInvalidArgs, + scriptError(ErrInvalidStackOperation, ""), nil, }, { @@ -699,7 +732,7 @@ func TestStack(t *testing.T) { func(s *stack) error { return s.OverN(1) }, - ErrStackUnderflow, + scriptError(ErrInvalidStackOperation, ""), nil, }, { @@ -708,7 +741,7 @@ func TestStack(t *testing.T) { func(s *stack) error { return s.OverN(0) }, - ErrStackInvalidArgs, + scriptError(ErrInvalidStackOperation, ""), nil, }, { @@ -735,7 +768,7 @@ func TestStack(t *testing.T) { func(s *stack) error { return s.PickN(1) }, - ErrStackUnderflow, + scriptError(ErrInvalidStackOperation, ""), nil, }, { @@ -762,7 +795,7 @@ func TestStack(t *testing.T) { func(s *stack) error { return s.RollN(1) }, - ErrStackUnderflow, + scriptError(ErrInvalidStackOperation, ""), nil, }, { @@ -865,32 +898,39 @@ func TestStack(t *testing.T) { _, err := s.PopInt() 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 7980b13c..60a3b907 100644 --- a/txscript/standard.go +++ b/txscript/standard.go @@ -1,10 +1,12 @@ -// Copyright (c) 2013-2016 The btcsuite developers +// Copyright (c) 2013-2017 The btcsuite developers // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. package txscript import ( + "fmt" + "github.com/btcsuite/btcd/chaincfg" "github.com/btcsuite/btcutil" ) @@ -243,9 +245,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") } si.ExpectedInputs = expectedInputs(pkPops, si.PkScriptClass) @@ -294,7 +297,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) @@ -328,34 +332,44 @@ func payToPubKeyScript(serializedPubKey []byte) ([]byte, error) { // PayToAddrScript creates a new script to pay a transaction output to a the // specified address. func PayToAddrScript(addr btcutil.Address) ([]byte, error) { + const nilAddrErrStr = "unable to generate payment script for nil address" + switch addr := addr.(type) { case *btcutil.AddressPubKeyHash: if addr == nil { - return nil, ErrUnsupportedAddress + return nil, scriptError(ErrUnsupportedAddress, + nilAddrErrStr) } return payToPubKeyHashScript(addr.ScriptAddress()) case *btcutil.AddressScriptHash: if addr == nil { - return nil, ErrUnsupportedAddress + return nil, scriptError(ErrUnsupportedAddress, + nilAddrErrStr) } return payToScriptHashScript(addr.ScriptAddress()) case *btcutil.AddressPubKey: if addr == nil { - return nil, ErrUnsupportedAddress + return nil, scriptError(ErrUnsupportedAddress, + nilAddrErrStr) } return payToPubKeyScript(addr.ScriptAddress()) } - return nil, ErrUnsupportedAddress + str := fmt.Sprintf("unable to generate payment script for unsupported "+ + "address type %T", addr) + return nil, scriptError(ErrUnsupportedAddress, str) } // NullDataScript creates a provably-prunable script containing OP_RETURN -// followed by the passed data. +// 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 NullDataScript(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() @@ -363,11 +377,14 @@ func NullDataScript(data []byte) ([]byte, error) { // 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. +// 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 []*btcutil.AddressPubKey, 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 226af172..917270af 100644 --- a/txscript/standard_test.go +++ b/txscript/standard_test.go @@ -1,4 +1,4 @@ -// Copyright (c) 2013-2016 The btcsuite developers +// Copyright (c) 2013-2017 The btcsuite developers // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. @@ -392,7 +392,7 @@ func TestCalcScriptInfo(t *testing.T) { pkScript: "HASH160 DATA_20 0xfe441065b6532231de2fac56" + "3152205ec4f59c", bip16: true, - scriptInfoErr: ErrStackShortScript, + scriptInfoErr: scriptError(ErrMalformedPush, ""), }, { name: "sigScript doesn't parse", @@ -402,7 +402,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 @@ -461,25 +461,19 @@ func TestCalcScriptInfo(t *testing.T) { for _, test := range tests { sigScript := mustParseShortForm(test.sigScript) pkScript := mustParseShortForm(test.pkScript) - si, err := CalcScriptInfo(sigScript, pkScript, - test.bip16) + 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 } } @@ -521,8 +515,7 @@ func TestPayToAddrScript(t *testing.T) { p2pkhMain, err := btcutil.NewAddressPubKeyHash(hexToBytes("e34cce70c86"+ "373273efcc54ce7d2a491bb4a0e84"), &chaincfg.MainNetParams) 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: @@ -530,8 +523,7 @@ func TestPayToAddrScript(t *testing.T) { p2shMain, _ := btcutil.NewAddressScriptHashFromHash(hexToBytes("e8c300"+ "c87986efa84c37c0519929019ef86eb5b4"), &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 @@ -539,17 +531,15 @@ func TestPayToAddrScript(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 := btcutil.NewAddressPubKey(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, err := btcutil.NewAddressPubKey(hexToBytes("0411"+ @@ -557,11 +547,14 @@ func TestPayToAddrScript(t *testing.T) { "cb2e0eaddfb84ccf9744464f82e160bfa9b8b64f9d4c03f999b8643f656b4"+ "12a3"), &chaincfg.MainNetParams) if err != nil { - t.Errorf("Unable to create pubkey address (uncompressed): %v", + t.Fatalf("Unable to create pubkey address (uncompressed): %v", err) - return } + // Errors used in the tests below defined here for convenience and to + // keep the horizontal test size shorter. + errUnsupportedAddress := scriptError(ErrUnsupportedAddress, "") + tests := []struct { in btcutil.Address expected string @@ -606,18 +599,18 @@ func TestPayToAddrScript(t *testing.T) { }, // Supported address types with nil pointers. - {(*btcutil.AddressPubKeyHash)(nil), "", ErrUnsupportedAddress}, - {(*btcutil.AddressScriptHash)(nil), "", ErrUnsupportedAddress}, - {(*btcutil.AddressPubKey)(nil), "", ErrUnsupportedAddress}, + {(*btcutil.AddressPubKeyHash)(nil), "", errUnsupportedAddress}, + {(*btcutil.AddressScriptHash)(nil), "", errUnsupportedAddress}, + {(*btcutil.AddressPubKey)(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 @@ -642,17 +635,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 := btcutil.NewAddressPubKey(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, err := btcutil.NewAddressPubKey(hexToBytes("0411"+ @@ -660,9 +651,8 @@ func TestMultiSigScript(t *testing.T) { "cb2e0eaddfb84ccf9744464f82e160bfa9b8b64f9d4c03f999b8643f656b4"+ "12a3"), &chaincfg.MainNetParams) if err != nil { - t.Errorf("Unable to create pubkey address (uncompressed): %v", + t.Fatalf("Unable to create pubkey address (uncompressed): %v", err) - return } tests := []struct { @@ -702,7 +692,7 @@ func TestMultiSigScript(t *testing.T) { }, 3, "", - ErrBadNumRequired, + scriptError(ErrTooManyRequiredSigs, ""), }, { []*btcutil.AddressPubKey{ @@ -721,16 +711,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 } @@ -757,14 +746,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", @@ -780,10 +769,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 } } } @@ -968,7 +958,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 } } } @@ -1082,17 +1072,18 @@ func TestNullDataScript(t *testing.T) { "728292a2b2c2d2e2f303132333435363738393a3b3c3" + "d3e3f404142434445464748494a4b4c4d4e4f50"), expected: nil, - err: ErrStackLongScript, + err: scriptError(ErrTooMuchNullData, ""), class: NonStandardTy, }, } for i, test := range tests { script, err := NullDataScript(test.data) - if err != test.err { - t.Errorf("NullDataScript: #%d (%s) unexpected error: "+ - "got %v, want %v", i, test.name, err, test.err) + if e := tstCheckScriptError(err, test.err); e != nil { + t.Errorf("NullDataScript: #%d (%s): %v", i, test.name, + e) continue + } // Check that the expected result was returned.