// Copyright (c) 2013-2017 The btcsuite developers // Copyright (c) 2015-2021 The Decred developers // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. package txscript import ( "errors" ) // ErrorKind identifies a kind of script error. type ErrorKind string // These constants are used to identify a specific ErrorKind. const ( // --------------------------------------- // Failures related to improper API usage. // --------------------------------------- // ErrInvalidIndex is returned when an out-of-bounds index is passed to // a function. ErrInvalidIndex = ErrorKind("ErrInvalidIndex") // ErrInvalidSigHashSingleIndex is returned when an attempt is // made to sign an input with the SigHashSingle hash type and an // index that is greater than or equal to the number of outputs. ErrInvalidSigHashSingleIndex = ErrorKind("ErrInvalidSigHashSingleIndex") // ErrUnsupportedScriptVersion is returned when an unsupported script // version is passed to a function which deals with script analysis. ErrUnsupportedScriptVersion = ErrorKind("ErrUnsupportedScriptVersion") // ------------------------------------------ // Failures related to final execution state. // ------------------------------------------ // ErrEarlyReturn is returned when OP_RETURN is executed in the script. ErrEarlyReturn = ErrorKind("ErrEarlyReturn") // ErrEmptyStack is returned when the script evaluated without error, // but terminated with an empty top stack element. ErrEmptyStack = ErrorKind("ErrEmptyStack") // ErrEvalFalse is returned when the script evaluated without error but // terminated with a false top stack element. ErrEvalFalse = ErrorKind("ErrEvalFalse") // ErrScriptUnfinished is returned when CheckErrorCondition is called on // a script that has not finished executing. ErrScriptUnfinished = ErrorKind("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 = ErrorKind("ErrInvalidProgramCounter") // ----------------------------------------------------- // Failures related to exceeding maximum allowed limits. // ----------------------------------------------------- // ErrScriptTooBig is returned if a script is larger than MaxScriptSize. ErrScriptTooBig = ErrorKind("ErrScriptTooBig") // ErrElementTooBig is returned if the size of an element to be pushed // to the stack is over MaxScriptElementSize. ErrElementTooBig = ErrorKind("ErrElementTooBig") // ErrTooManyOperations is returned if a script has more than // MaxOpsPerScript opcodes that do not push data. ErrTooManyOperations = ErrorKind("ErrTooManyOperations") // ErrStackOverflow is returned when stack and altstack combined depth // is over the limit. ErrStackOverflow = ErrorKind("ErrStackOverflow") // ErrInvalidPubKeyCount is returned when the number of public keys // specified for a multsig is either negative or greater than // MaxPubKeysPerMultiSig. ErrInvalidPubKeyCount = ErrorKind("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 = ErrorKind("ErrInvalidSignatureCount") // ErrNumOutOfRange is returned when the argument for an opcode that // expects numeric input is larger than the expected maximum number of // bytes. For the most part, opcodes that deal with stack manipulation // via offsets, arithmetic, numeric comparison, and boolean logic are // those that this applies to. However, any opcode that expects numeric // input may fail with this error. ErrNumOutOfRange = ErrorKind("ErrNumOutOfRange") // -------------------------------------------- // Failures related to verification operations. // -------------------------------------------- // ErrVerify is returned when OP_VERIFY is encountered in a script and // the top item on the data stack does not evaluate to true. ErrVerify = ErrorKind("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 = ErrorKind("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 = ErrorKind("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 = ErrorKind("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 = ErrorKind("ErrCheckMultiSigVerify") // ErrCheckSigAltVerify is returned when OP_CHECKSIGALTVERIFY is // encountered in a script and the top item on the data stack does not // evaluate to true. ErrCheckSigAltVerify = ErrorKind("ErrCheckSigAltVerify") // -------------------------------------------- // Failures related to improper use of opcodes. // -------------------------------------------- // ErrP2SHStakeOpCodes is returned when one or more stake opcodes are // found in the redeem script of a pay-to-script-hash script. ErrP2SHStakeOpCodes = ErrorKind("ErrP2SHStakeOpCodes") // ErrDisabledOpcode is returned when a disabled opcode is encountered // in a script. ErrDisabledOpcode = ErrorKind("ErrDisabledOpcode") // ErrReservedOpcode is returned when an opcode marked as reserved // is encountered in a script. ErrReservedOpcode = ErrorKind("ErrReservedOpcode") // ErrMalformedPush is returned when a data push opcode tries to push // more bytes than are left in the script. ErrMalformedPush = ErrorKind("ErrMalformedPush") // ErrInvalidStackOperation is returned when a stack operation is // attempted with a number that is invalid for the current stack size. ErrInvalidStackOperation = ErrorKind("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 = ErrorKind("ErrUnbalancedConditional") // ErrNegativeSubstrIdx is returned when an OP_SUBSTR, OP_LEFT, or // OP_RIGHT opcode encounters a negative index. ErrNegativeSubstrIdx = ErrorKind("ErrNegativeSubstrIdx") // ErrOverflowSubstrIdx is returned when an OP_SUBSTR, OP_LEFT, or // OP_RIGHT opcode encounters an index that is larger than the max // allowed index that can operate on the string or the start index // is greater than the end index for OP_SUBSTR. ErrOverflowSubstrIdx = ErrorKind("ErrOverflowSubstrIdx") // ErrNegativeRotation is returned when an OP_ROTL or OP_ROTR attempts // to perform a rotation with a negative rotation count. ErrNegativeRotation = ErrorKind("ErrNegativeRotation") // ErrOverflowRotation is returned when an OP_ROTL or OP_ROTR opcode // encounters a rotation count that is larger than the maximum allowed // value for a uint32 bit rotation. ErrOverflowRotation = ErrorKind("ErrOverflowRotation") // ErrDivideByZero is returned when an OP_DIV of OP_MOD attempts to // divide by zero. ErrDivideByZero = ErrorKind("ErrDivideByZero") // ErrNegativeRotation is returned when an OP_LSHIFT or OP_RSHIFT opcode // attempts to perform a shift with a negative count. ErrNegativeShift = ErrorKind("ErrNegativeShift") // ErrOverflowShift is returned when an OP_LSHIFT or OP_RSHIFT opcode // encounters a shift count that is larger than the maximum allowed value // for a shift. ErrOverflowShift = ErrorKind("ErrOverflowShift") // ErrP2SHTreasuryOpCodes is returned when one or more treasury opcodes // are found in the redeem script of a pay-to-script-hash script. ErrP2SHTreasuryOpCodes = ErrorKind("ErrP2SHTreasuryOpCodes") // --------------------------------- // Failures related to malleability. // --------------------------------- // ErrMinimalData is returned when the script contains push operations // that do not use the minimal opcode required. ErrMinimalData = ErrorKind("ErrMinimalData") // ErrInvalidSigHashType is returned when a signature hash type is not // one of the supported types. ErrInvalidSigHashType = ErrorKind("ErrInvalidSigHashType") // ErrSigTooShort is returned when a signature that should be a // canonically-encoded DER signature is too short. ErrSigTooShort = ErrorKind("ErrSigTooShort") // ErrSigTooLong is returned when a signature that should be a // canonically-encoded DER signature is too long. ErrSigTooLong = ErrorKind("ErrSigTooLong") // ErrSigInvalidSeqID is returned when a signature that should be a // canonically-encoded DER signature does not have the expected ASN.1 // sequence ID. ErrSigInvalidSeqID = ErrorKind("ErrSigInvalidSeqID") // ErrSigInvalidDataLen is returned when a signature that should be a // canonically-encoded DER signature does not specify the correct number // of remaining bytes for the R and S portions. ErrSigInvalidDataLen = ErrorKind("ErrSigInvalidDataLen") // ErrSigMissingSTypeID is returned when a signature that should be a // canonically-encoded DER signature does not provide the ASN.1 type ID // for S. ErrSigMissingSTypeID = ErrorKind("ErrSigMissingSTypeID") // ErrSigMissingSLen is returned when a signature that should be a // canonically-encoded DER signature does not provide the length of S. ErrSigMissingSLen = ErrorKind("ErrSigMissingSLen") // ErrSigInvalidSLen is returned when a signature that should be a // canonically-encoded DER signature does not specify the correct number // of bytes for the S portion. ErrSigInvalidSLen = ErrorKind("ErrSigInvalidSLen") // ErrSigInvalidRIntID is returned when a signature that should be a // canonically-encoded DER signature does not have the expected ASN.1 // integer ID for R. ErrSigInvalidRIntID = ErrorKind("ErrSigInvalidRIntID") // ErrSigZeroRLen is returned when a signature that should be a // canonically-encoded DER signature has an R length of zero. ErrSigZeroRLen = ErrorKind("ErrSigZeroRLen") // ErrSigNegativeR is returned when a signature that should be a // canonically-encoded DER signature has a negative value for R. ErrSigNegativeR = ErrorKind("ErrSigNegativeR") // ErrSigTooMuchRPadding is returned when a signature that should be a // canonically-encoded DER signature has too much padding for R. ErrSigTooMuchRPadding = ErrorKind("ErrSigTooMuchRPadding") // ErrSigInvalidSIntID is returned when a signature that should be a // canonically-encoded DER signature does not have the expected ASN.1 // integer ID for S. ErrSigInvalidSIntID = ErrorKind("ErrSigInvalidSIntID") // ErrSigZeroSLen is returned when a signature that should be a // canonically-encoded DER signature has an S length of zero. ErrSigZeroSLen = ErrorKind("ErrSigZeroSLen") // ErrSigNegativeS is returned when a signature that should be a // canonically-encoded DER signature has a negative value for S. ErrSigNegativeS = ErrorKind("ErrSigNegativeS") // ErrSigTooMuchSPadding is returned when a signature that should be a // canonically-encoded DER signature has too much padding for S. ErrSigTooMuchSPadding = ErrorKind("ErrSigTooMuchSPadding") // ErrSigHighS is returned when a signature that should be a // canonically-encoded DER signature has an S value that is higher than // the curve half order. ErrSigHighS = ErrorKind("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 = ErrorKind("ErrNotPushOnly") // ErrPubKeyType is returned when the script contains invalid public keys. ErrPubKeyType = ErrorKind("ErrPubKeyType") // ErrCleanStack is returned when the ScriptVerifyCleanStack flag // is set, and after evaluation, the stack does not contain only a // single element. ErrCleanStack = ErrorKind("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 = ErrorKind("ErrDiscourageUpgradableNOPs") // ErrNegativeLockTime is returned when a script contains an opcode that // interprets a negative lock time. ErrNegativeLockTime = ErrorKind("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 = ErrorKind("ErrUnsatisfiedLockTime") ) // Error satisfies the error interface and prints human-readable errors. func (e ErrorKind) Error() string { return string(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 // // It has full support for errors.Is and errors.As, so the caller can ascertain // the specific reason for the error by checking the underlying error. type Error struct { Err error Description string } // Error satisfies the error interface and prints human-readable errors. func (e Error) Error() string { return e.Description } // Unwrap returns the underlying wrapped error. func (e Error) Unwrap() error { return e.Err } // scriptError creates a ScriptError given a set of arguments. func scriptError(kind ErrorKind, desc string) Error { return Error{Err: kind, Description: desc} } // IsDERSigError returns whether or not the provided error is one of the error // kinds which are caused due to encountering a signature that is not a // canonically-encoded DER signature. func IsDERSigError(err error) bool { var kind ErrorKind if !errors.As(err, &kind) { return false } switch kind { case ErrSigTooShort, ErrSigTooLong, ErrSigInvalidSeqID, ErrSigInvalidDataLen, ErrSigMissingSTypeID, ErrSigMissingSLen, ErrSigInvalidSLen, ErrSigInvalidRIntID, ErrSigZeroRLen, ErrSigNegativeR, ErrSigTooMuchRPadding, ErrSigInvalidSIntID, ErrSigZeroSLen, ErrSigNegativeS, ErrSigTooMuchSPadding, ErrSigHighS: return true } return false }