Skip to content

Commit

Permalink
blockchain/stake: update error types.
Browse files Browse the repository at this point in the history
This updates the stake error types to leverage go
1.13 errors.Is/As functionality as well as confirm
to the error infrastructure best practices.
  • Loading branch information
dnldd committed Jul 19, 2020
1 parent 5616620 commit a1f4241
Show file tree
Hide file tree
Showing 6 changed files with 440 additions and 412 deletions.
164 changes: 57 additions & 107 deletions blockchain/stake/error.go
Original file line number Diff line number Diff line change
@@ -1,255 +1,205 @@
// Copyright (c) 2014 Conformal Systems LLC.
// Copyright (c) 2015-2016 The Decred developers
// Copyright (c) 2015-2020 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package stake

import (
"fmt"
)

// ErrorCode identifies a kind of error.
type ErrorCode int
// 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 = iota
ErrSStxTooManyInputs = ErrorKind("ErrSStxTooManyInputs")

// ErrSStxTooManyOutputs indicates that a given SStx contains too many
// outputs.
ErrSStxTooManyOutputs
ErrSStxTooManyOutputs = ErrorKind("ErrSStxTooManyOutputs")

// ErrSStxNoOutputs indicates that a given SStx has no outputs.
ErrSStxNoOutputs
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
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
ErrSStxInvalidOutputs = ErrorKind("ErrSStxInvalidOutputs")

// ErrSStxInOutProportions indicates the number of inputs in an SStx
// was not equal to the number of output minus one.
ErrSStxInOutProportions
ErrSStxInOutProportions = ErrorKind("ErrSStxInOutProportions")

// ErrSStxBadCommitAmount indicates that a ticket tried to commit 0 or
// a negative value as the commitment amount.
ErrSStxBadCommitAmount
ErrSStxBadCommitAmount = ErrorKind("ErrSStxBadCommitAmount")

// ErrSStxBadChangeAmts indicates that the change amount for some SStx
// was invalid, for instance spending more than its inputs.
ErrSStxBadChangeAmts
ErrSStxBadChangeAmts = ErrorKind("ErrSStxBadChangeAmts")

// ErrSStxVerifyCalcAmts indicates that passed calculated amounts failed
// to conform to the amounts found in the ticket.
ErrSStxVerifyCalcAmts
ErrSStxVerifyCalcAmts = ErrorKind("ErrSStxVerifyCalcAmts")

// ErrSSGenWrongNumInputs indicates that a given SSGen tx contains an
// invalid number of inputs.
ErrSSGenWrongNumInputs
ErrSSGenWrongNumInputs = ErrorKind("ErrSSGenWrongNumInputs")

// ErrSSGenTooManyOutputs indicates that a given SSGen tx contains too
// many outputs.
ErrSSGenTooManyOutputs
ErrSSGenTooManyOutputs = ErrorKind("ErrSSGenTooManyOutputs")

// ErrSSGenNoOutputs indicates that a given SSGen has no outputs.
ErrSSGenNoOutputs
ErrSSGenNoOutputs = ErrorKind("ErrSSGenNoOutputs")

// ErrSSGenWrongIndex indicates that a given SSGen sstx input was not
// using the correct index.
ErrSSGenWrongIndex
ErrSSGenWrongIndex = ErrorKind("ErrSSGenWrongIndex")

// ErrSSGenWrongTxTree indicates that a given SSGen tx input was not found in
// the stake tx tree.
ErrSSGenWrongTxTree
ErrSSGenWrongTxTree = ErrorKind("ErrSSGenWrongTxTree")

// ErrSSGenNoStakebase indicates that the SSGen tx did not contain a
// valid StakeBase in the zeroeth position of inputs.
ErrSSGenNoStakebase
ErrSSGenNoStakebase = ErrorKind("ErrSSGenNoStakebase")

// ErrSSGenNoReference indicates that there is no reference OP_RETURN
// included as the first output.
ErrSSGenNoReference
ErrSSGenNoReference = ErrorKind("ErrSSGenNoReference")

// ErrSSGenNoReference indicates that the OP_RETURN included as the
// first output was corrupted in some way.
ErrSSGenBadReference
ErrSSGenBadReference = ErrorKind("ErrSSGenBadReference")

// ErrSSGenNoVotePush indicates that there is no vote bits OP_RETURN
// included as the second output.
ErrSSGenNoVotePush
ErrSSGenNoVotePush = ErrorKind("ErrSSGenNoVotePush")

// ErrSSGenBadVotePush indicates that the OP_RETURN included as the
// second output was corrupted in some way.
ErrSSGenBadVotePush
ErrSSGenBadVotePush = ErrorKind("ErrSSGenBadVotePush")

// ErrSSGenBadGenOuts indicates that the something was wrong with the
// stake generation outputs that were present after the first two
// OP_RETURN pushes in an SSGen tx.
ErrSSGenBadGenOuts
ErrSSGenBadGenOuts = ErrorKind("ErrSSGenBadGenOuts")

// ErrSSRtxWrongNumInputs indicates that a given SSRtx contains an
// invalid number of inputs.
ErrSSRtxWrongNumInputs
ErrSSRtxWrongNumInputs = ErrorKind("ErrSSRtxWrongNumInputs")

// ErrSSRtxTooManyOutputs indicates that a given SSRtx contains too many
// outputs.
ErrSSRtxTooManyOutputs
ErrSSRtxTooManyOutputs = ErrorKind("ErrSSRtxTooManyOutputs")

// ErrSSRtxNoOutputs indicates that a given SSRtx has no outputs.
ErrSSRtxNoOutputs
ErrSSRtxNoOutputs = ErrorKind("ErrSSRtxNoOutputs")

// ErrSSRtxWrongTxTree indicates that a given SSRtx input was not found in
// the stake tx tree.
ErrSSRtxWrongTxTree
ErrSSRtxWrongTxTree = ErrorKind("ErrSSRtxWrongTxTree")

// ErrSSRtxBadGenOuts indicates that there was a non-SSRtx tagged output
// present in an SSRtx.
ErrSSRtxBadOuts
ErrSSRtxBadOuts = ErrorKind("ErrSSRtxBadOuts")

// ErrVerSStxAmts indicates there was an error verifying the calculated
// SStx out amounts and the actual SStx out amounts.
ErrVerSStxAmts
ErrVerSStxAmts = ErrorKind("ErrVerSStxAmts")

// ErrVerifyInput indicates that there was an error in verification
// function input.
ErrVerifyInput
ErrVerifyInput = ErrorKind("ErrVerifyInput")

// ErrVerifyOutType indicates that there was a non-equivalence in the
// output type.
ErrVerifyOutType
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
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
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
ErrVerifyOutputAmt = ErrorKind("ErrVerifyOutputAmt")

// ErrVerifyOutPkhs indicates that the recipient of the P2PKH or P2SH
// script was different from that indicated in the SStx input.
ErrVerifyOutPkhs
ErrVerifyOutPkhs = ErrorKind("ErrVerifyOutPkhs")

// ErrDatabaseCorrupt indicates a database inconsistency.
ErrDatabaseCorrupt
ErrDatabaseCorrupt = ErrorKind("ErrDatabaseCorrupt")

// ErrMissingDatabaseTx indicates that a node disconnection failed to
// pass a database transaction when attempted to remove a very old
// node.
ErrMissingDatabaseTx
ErrMissingDatabaseTx = ErrorKind("ErrMissingDatabaseTx")

// ErrMemoryCorruption indicates that memory has somehow become corrupt,
// for example invalid block header serialization from an in memory
// struct.
ErrMemoryCorruption
ErrMemoryCorruption = ErrorKind("ErrMemoryCorruption")

// ErrFindTicketIdxs indicates a failure to find the selected ticket
// indexes from the block header.
ErrFindTicketIdxs
ErrFindTicketIdxs = ErrorKind("ErrFindTicketIdxs")

// ErrMissingTicket indicates that a ticket was missing in one of the
// ticket treaps when it was attempted to be fetched.
ErrMissingTicket
ErrMissingTicket = ErrorKind("ErrMissingTicket")

// ErrDuplicateTicket indicates that a duplicate ticket was attempted
// to be inserted into a ticket treap or the database.
ErrDuplicateTicket
ErrDuplicateTicket = ErrorKind("ErrDuplicateTicket")

// ErrUnknownTicketSpent indicates that an unknown ticket was spent by
// the block.
ErrUnknownTicketSpent
ErrUnknownTicketSpent = ErrorKind("ErrUnknownTicketSpent")
)

// Map of ErrorCode values back to their constant names for pretty printing.
var errorCodeStrings = map[ErrorCode]string{
ErrSStxTooManyInputs: "ErrSStxTooManyInputs",
ErrSStxTooManyOutputs: "ErrSStxTooManyOutputs",
ErrSStxNoOutputs: "ErrSStxNoOutputs",
ErrSStxInvalidInputs: "ErrSStxInvalidInputs",
ErrSStxInvalidOutputs: "ErrSStxInvalidOutputs",
ErrSStxInOutProportions: "ErrSStxInOutProportions",
ErrSStxBadCommitAmount: "ErrSStxBadCommitAmount",
ErrSStxBadChangeAmts: "ErrSStxBadChangeAmts",
ErrSStxVerifyCalcAmts: "ErrSStxVerifyCalcAmts",
ErrSSGenWrongNumInputs: "ErrSSGenWrongNumInputs",
ErrSSGenTooManyOutputs: "ErrSSGenTooManyOutputs",
ErrSSGenNoOutputs: "ErrSSGenNoOutputs",
ErrSSGenWrongIndex: "ErrSSGenWrongIndex",
ErrSSGenWrongTxTree: "ErrSSGenWrongTxTree",
ErrSSGenNoStakebase: "ErrSSGenNoStakebase",
ErrSSGenNoReference: "ErrSSGenNoReference",
ErrSSGenBadReference: "ErrSSGenBadReference",
ErrSSGenNoVotePush: "ErrSSGenNoVotePush",
ErrSSGenBadVotePush: "ErrSSGenBadVotePush",
ErrSSGenBadGenOuts: "ErrSSGenBadGenOuts",
ErrSSRtxWrongNumInputs: "ErrSSRtxWrongNumInputs",
ErrSSRtxTooManyOutputs: "ErrSSRtxTooManyOutputs",
ErrSSRtxNoOutputs: "ErrSSRtxNoOutputs",
ErrSSRtxWrongTxTree: "ErrSSRtxWrongTxTree",
ErrSSRtxBadOuts: "ErrSSRtxBadOuts",
ErrVerSStxAmts: "ErrVerSStxAmts",
ErrVerifyInput: "ErrVerifyInput",
ErrVerifyOutType: "ErrVerifyOutType",
ErrVerifyTooMuchFees: "ErrVerifyTooMuchFees",
ErrVerifySpendTooMuch: "ErrVerifySpendTooMuch",
ErrVerifyOutputAmt: "ErrVerifyOutputAmt",
ErrVerifyOutPkhs: "ErrVerifyOutPkhs",
ErrDatabaseCorrupt: "ErrDatabaseCorrupt",
ErrMissingDatabaseTx: "ErrMissingDatabaseTx",
ErrMemoryCorruption: "ErrMemoryCorruption",
ErrFindTicketIdxs: "ErrFindTicketIdxs",
ErrMissingTicket: "ErrMissingTicket",
ErrDuplicateTicket: "ErrDuplicateTicket",
ErrUnknownTicketSpent: "ErrUnknownTicketSpent",
}

// 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 satisfies the error interface and prints human-readable errors.
func (e ErrorKind) Error() string {
return string(e)
}

// RuleError identifies a rule violation. It is used to indicate that
// processing of a block or transaction failed due to one of the many validation
// rules. The caller can use type assertions to determine if a failure was
// specifically due to a rule violation and access the ErrorCode field to
// ascertain the specific reason for the rule violation.
// 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 {
ErrorCode ErrorCode // Describes the kind of error
Description string // Human readable description of the issue
Description string
Err error
}

// Error satisfies the error interface and prints human-readable errors.
func (e RuleError) Error() string {
return e.Description
}

// GetCode satisfies the error interface and prints human-readable errors.
func (e RuleError) GetCode() ErrorCode {
return e.ErrorCode
// 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(c ErrorCode, desc string) RuleError {
return RuleError{ErrorCode: c, Description: desc}
func stakeRuleError(kind ErrorKind, desc string) RuleError {
return RuleError{Err: kind, Description: desc}
}
Loading

0 comments on commit a1f4241

Please sign in to comment.