// Copyright (c) 2014 Conformal Systems LLC. // 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 stake // ErrorKind identifies a kind of error. It has full support for errors.Is and // errors.As, so the caller can directly check against an error kind when // determining the reason for an error. type ErrorKind string // These constants are used to identify a specific RuleError. const ( // ErrSStxTooManyInputs indicates that a given SStx contains too many // inputs. ErrSStxTooManyInputs = ErrorKind("ErrSStxTooManyInputs") // ErrSStxTooManyOutputs indicates that a given SStx contains too many // outputs. ErrSStxTooManyOutputs = ErrorKind("ErrSStxTooManyOutputs") // ErrSStxNoOutputs indicates that a given SStx has no outputs. ErrSStxNoOutputs = ErrorKind("ErrSStxNoOutputs") // ErrSStxInvalidInput indicates that an invalid output has been used as // an input for a SStx; only non-SStx tagged outputs may be used to // purchase stake tickets. // TODO: Add this into validate // Ensure that all inputs are not tagged SStx outputs of some sort, // along with checks to make sure they exist and are available. ErrSStxInvalidInputs = ErrorKind("ErrSStxInvalidInputs") // ErrSStxInvalidOutput indicates that the output for an SStx tx is // invalid; in particular, either the output was not tagged SStx or the // OP_RETURNs were missing or contained invalid addresses. ErrSStxInvalidOutputs = ErrorKind("ErrSStxInvalidOutputs") // ErrSStxInOutProportions indicates the number of inputs in an SStx // was not equal to the number of output minus one. ErrSStxInOutProportions = ErrorKind("ErrSStxInOutProportions") // ErrSStxBadCommitAmount indicates that a ticket tried to commit 0 or // a negative value as the commitment amount. ErrSStxBadCommitAmount = ErrorKind("ErrSStxBadCommitAmount") // ErrSStxBadChangeAmts indicates that the change amount for some SStx // was invalid, for instance spending more than its inputs. ErrSStxBadChangeAmts = ErrorKind("ErrSStxBadChangeAmts") // ErrSStxVerifyCalcAmts indicates that passed calculated amounts failed // to conform to the amounts found in the ticket. ErrSStxVerifyCalcAmts = ErrorKind("ErrSStxVerifyCalcAmts") // ErrSSGenWrongNumInputs indicates that a given SSGen tx contains an // invalid number of inputs. ErrSSGenWrongNumInputs = ErrorKind("ErrSSGenWrongNumInputs") // ErrSSGenTooManyOutputs indicates that a given SSGen tx contains too // many outputs. ErrSSGenTooManyOutputs = ErrorKind("ErrSSGenTooManyOutputs") // ErrSSGenNoOutputs indicates that a given SSGen has no outputs. ErrSSGenNoOutputs = ErrorKind("ErrSSGenNoOutputs") // ErrSSGenWrongIndex indicates that a given SSGen sstx input was not // using the correct index. ErrSSGenWrongIndex = ErrorKind("ErrSSGenWrongIndex") // ErrSSGenWrongTxTree indicates that a given SSGen tx input was not found in // the stake tx tree. ErrSSGenWrongTxTree = ErrorKind("ErrSSGenWrongTxTree") // ErrSSGenNoStakebase indicates that the SSGen tx did not contain a // valid StakeBase in the zeroeth position of inputs. ErrSSGenNoStakebase = ErrorKind("ErrSSGenNoStakebase") // ErrSSGenNoReference indicates that there is no reference OP_RETURN // included as the first output. ErrSSGenNoReference = ErrorKind("ErrSSGenNoReference") // ErrSSGenNoReference indicates that the OP_RETURN included as the // first output was corrupted in some way. ErrSSGenBadReference = ErrorKind("ErrSSGenBadReference") // ErrSSGenNoVotePush indicates that there is no vote bits OP_RETURN // included as the second output. ErrSSGenNoVotePush = ErrorKind("ErrSSGenNoVotePush") // ErrSSGenBadVotePush indicates that the OP_RETURN included as the // second output was corrupted in some way. ErrSSGenBadVotePush = ErrorKind("ErrSSGenBadVotePush") // ErrSSGenInvalidDiscriminatorLength indicates that the discriminator // length is too short. ErrSSGenInvalidDiscriminatorLength = ErrorKind("ErrSSGenInvalidDiscriminatorLength") // ErrSSGenInvalidNullScript indicates that the passed script is not a // valid nullscript. ErrSSGenInvalidNullScript = ErrorKind("ErrSSGenInvalidNullScript") // ErrSSGenInvalidTVLength indicates that this is an invalid Treasury // Vote length. ErrSSGenInvalidTVLength = ErrorKind("ErrSSGenInvalidTVLength") // ErrSSGenInvalidTreasuryVote indicates that this is an invalid // treasury vote. ErrSSGenInvalidTreasuryVote = ErrorKind("ErrSSGenInvalidTreasuryVote") // ErrSSGenDuplicateTreasuryVote indicates that there is a duplicate // treasury vote. ErrSSGenDuplicateTreasuryVote = ErrorKind("ErrSSGenDuplicateTreasuryVote") // ErrSSGenInvalidTxVersion indicates that this transaction has the // wrong version. ErrSSGenInvalidTxVersion = ErrorKind("ErrSSGenInvalidTxVersion") // ErrSSGenUnknownDiscriminator indicates that the supplied // discriminator is unsupported. ErrSSGenUnknownDiscriminator = ErrorKind("ErrSSGenUnknownDiscriminator") // ErrSSGenBadGenOuts indicates that something was wrong with the stake // generation outputs that were present after the first two OP_RETURN // pushes in an SSGen tx. ErrSSGenBadGenOuts = ErrorKind("ErrSSGenBadGenOuts") // ErrSSRtxWrongNumInputs indicates that a given SSRtx contains an // invalid number of inputs. ErrSSRtxWrongNumInputs = ErrorKind("ErrSSRtxWrongNumInputs") // ErrSSRtxTooManyOutputs indicates that a given SSRtx contains too many // outputs. ErrSSRtxTooManyOutputs = ErrorKind("ErrSSRtxTooManyOutputs") // ErrSSRtxNoOutputs indicates that a given SSRtx has no outputs. ErrSSRtxNoOutputs = ErrorKind("ErrSSRtxNoOutputs") // ErrSSRtxWrongTxTree indicates that a given SSRtx input was not found in // the stake tx tree. ErrSSRtxWrongTxTree = ErrorKind("ErrSSRtxWrongTxTree") // ErrSSRtxBadOuts indicates that there was a non-SSRtx tagged output // present in an SSRtx. ErrSSRtxBadOuts = ErrorKind("ErrSSRtxBadOuts") // ErrSSRtxInvalidFee indicates that a given SSRtx contains an invalid fee. ErrSSRtxInvalidFee = ErrorKind("ErrSSRtxInvalidFee") // ErrSSRtxInputHasSigScript indicates that a given SSRtx input has a // non-empty signature script. ErrSSRtxInputHasSigScript = ErrorKind("ErrSSRtxInputHasSigScript") // ErrSSRtxInvalidTxVersion indicates that a given SSRtx has an invalid // transaction version. ErrSSRtxInvalidTxVersion = ErrorKind("ErrSSRtxInvalidTxVersion") // ErrVerSStxAmts indicates there was an error verifying the calculated // SStx out amounts and the actual SStx out amounts. ErrVerSStxAmts = ErrorKind("ErrVerSStxAmts") // ErrVerifyInput indicates that there was an error in verification // function input. ErrVerifyInput = ErrorKind("ErrVerifyInput") // ErrVerifyOutType indicates that there was a non-equivalence in the // output type. ErrVerifyOutType = ErrorKind("ErrVerifyOutType") // ErrVerifyTooMuchFees indicates that a transaction's output gave // too much in fees after taking into accounts the limits imposed // by the SStx output's version field. ErrVerifyTooMuchFees = ErrorKind("ErrVerifyTooMuchFees") // ErrVerifySpendTooMuch indicates that a transaction's output spent more // than it was allowed to spend based on the calculated subsidy or return // for a vote or revocation. ErrVerifySpendTooMuch = ErrorKind("ErrVerifySpendTooMuch") // ErrVerifyOutputAmt indicates that for a vote/revocation spend output, // the rule was given that it must exactly match the calculated maximum, // however the amount in the output did not (e.g. it gave fees). ErrVerifyOutputAmt = ErrorKind("ErrVerifyOutputAmt") // ErrVerifyOutPkhs indicates that the recipient of the P2PKH or P2SH // script was different from that indicated in the SStx input. ErrVerifyOutPkhs = ErrorKind("ErrVerifyOutPkhs") // ErrDatabaseCorrupt indicates a database inconsistency. ErrDatabaseCorrupt = ErrorKind("ErrDatabaseCorrupt") // ErrMissingDatabaseTx indicates that a node disconnection failed to // pass a database transaction when attempted to remove a very old // node. ErrMissingDatabaseTx = ErrorKind("ErrMissingDatabaseTx") // ErrMemoryCorruption indicates that memory has somehow become corrupt, // for example invalid block header serialization from an in memory // struct. ErrMemoryCorruption = ErrorKind("ErrMemoryCorruption") // ErrFindTicketIdxs indicates a failure to find the selected ticket // indexes from the block header. ErrFindTicketIdxs = ErrorKind("ErrFindTicketIdxs") // ErrMissingTicket indicates that a ticket was missing in one of the // ticket treaps when it was attempted to be fetched. ErrMissingTicket = ErrorKind("ErrMissingTicket") // ErrDuplicateTicket indicates that a duplicate ticket was attempted // to be inserted into a ticket treap or the database. ErrDuplicateTicket = ErrorKind("ErrDuplicateTicket") // ErrUnknownTicketSpent indicates that an unknown ticket was spent by // the block. ErrUnknownTicketSpent = ErrorKind("ErrUnknownTicketSpent") // ErrTAddInvalidTxVersion indicates that this transaction has the // wrong version. ErrTAddInvalidTxVersion = ErrorKind("ErrTAddInvalidTxVersion") // ErrTAddInvalidCount indicates that this transaction contains an // invalid TADD script count. ErrTAddInvalidCount = ErrorKind("ErrTAddInvalidCount") // ErrTAddInvalidVersion indicates that this transaction has an invalid // version in an output script. ErrTAddInvalidVersion = ErrorKind("ErrTAddInvalidVersion") // ErrTAddInvalidScriptLength indicates that this transaction has a zero // length output script. ErrTAddInvalidScriptLength = ErrorKind("ErrTAddInvalidScriptLength") // ErrTAddInvalidLength indicates that output 0 is not exactly 1 byte. ErrTAddInvalidLength = ErrorKind("ErrTAddInvalidLength") // ErrTAddInvalidOpcode indicates that this transaction does not have a // TADD opcode. ErrTAddInvalidOpcode = ErrorKind("ErrTAddInvalidOpcode") // ErrTAddInvalidChange indicates that this transaction contains an // invalid change script. ErrTAddInvalidChange = ErrorKind("ErrTAddInvalidChange") // ErrTSpendInvalidTxVersion indicates that this transaction has // the wrong version. ErrTSpendInvalidTxVersion = ErrorKind("ErrTSpendInvalidTxVersion") // ErrTSpendInvalidLength indicates that this transaction has an // invalid number of inputs and/or outputs. ErrTSpendInvalidLength = ErrorKind("ErrTSpendInvalidLength") // ErrTSpendInvalidVersion indicates that this transaction has an // invalid version in an output script. ErrTSpendInvalidVersion = ErrorKind("ErrTSpendInvalidVersion") // ErrTSpendInvalidScriptLength indicates that the TSPEND transaction // has outputs that have a zero length script. ErrTSpendInvalidScriptLength = ErrorKind("ErrTSpendInvalidScriptLength") // ErrTSpendInvalidPubkey indicates that this transaction contains an // invalid public key. ErrTSpendInvalidPubkey = ErrorKind("ErrTSpendInvalidPubkey") // ErrTSpendInvalidScript indicates that this transaction does not // match the required TSPEND transaction signature. ErrTSpendInvalidScript = ErrorKind("ErrTSpendInvalidScript") // ErrTSpendInvalidTGen indicates that the TSPEND transaction has // outputs that are not tagged with OP_TGEN. ErrTSpendInvalidTGen = ErrorKind("ErrTSpendInvalidTGen") // ErrTSpendInvalidTransaction indicates that a TSPEND transaction // output 0 does not have an a valid null data script. ErrTSpendInvalidTransaction = ErrorKind("ErrTSpendInvalidTransaction") // ErrTSpendInvalidSpendScript indicates that this transaction contains // an invalid P2SH or P2PKH script. ErrTSpendInvalidSpendScript = ErrorKind("ErrTSpendInvalidSpendScript") // ErrTreasuryBaseInvalidTxVersion indicates that this transaction has // the wrong version. ErrTreasuryBaseInvalidTxVersion = ErrorKind("ErrTreasuryBaseInvalidTxVersion") // ErrTreasuryBaseInvalidCount indicates that this transaction contains // an invalid treasury base script count. ErrTreasuryBaseInvalidCount = ErrorKind("ErrTreasuryBaseInvalidCount") // ErrTreasuryBaseInvalidLength indicates that this transaction contains // an invalid treasury base input script length. ErrTreasuryBaseInvalidLength = ErrorKind("ErrTreasuryBaseInvalidLength") // ErrTreasuryBaseInvalidVersion indicates that this transaction has an // invalid version in an output script. ErrTreasuryBaseInvalidVersion = ErrorKind("ErrTreasuryBaseInvalidVersion") // ErrTreasuryBaseInvalidOpcode0 indicates that this transaction does // not have a TADD opcode in TxOut[0]. ErrTreasuryBaseInvalidOpcode0 = ErrorKind("ErrTreasuryBaseInvalidOpcode0") // ErrTreasuryBaseInvalidOpcode1 indicates that this transaction does // not have an OP_RETURN opcode in TxOut[1]. ErrTreasuryBaseInvalidOpcode1 = ErrorKind("ErrTreasuryBaseInvalidOpcode1") // ErrTreasuryBaseInvalid indicates that this transaction contains // invalid treasurybase TxIn constants. ErrTreasuryBaseInvalid = ErrorKind("ErrTreasuryBaseInvalid") ) // Error satisfies the error interface and prints human-readable errors. func (e ErrorKind) Error() string { return string(e) } // RuleError identifies a rule violation related to stake transactions. 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 RuleError struct { Description string Err error } // Error satisfies the error interface and prints human-readable errors. func (e RuleError) Error() string { return e.Description } // Unwrap returns the underlying wrapped rule error. func (e RuleError) Unwrap() error { return e.Err } // stakeRuleError creates a RuleError given a set of arguments. func stakeRuleError(kind ErrorKind, desc string) RuleError { return RuleError{Err: kind, Description: desc} }