diff --git a/blockchain/stake/error.go b/blockchain/stake/error.go index 2b6a904be4..7ef1232425 100644 --- a/blockchain/stake/error.go +++ b/blockchain/stake/error.go @@ -1,29 +1,27 @@ // 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 @@ -31,212 +29,164 @@ const ( // 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. @@ -244,12 +194,12 @@ 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} } diff --git a/blockchain/stake/error_test.go b/blockchain/stake/error_test.go index 4f427190c2..8e2226b5b1 100644 --- a/blockchain/stake/error_test.go +++ b/blockchain/stake/error_test.go @@ -1,70 +1,67 @@ // 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_test +package stake import ( + "errors" + "io" "testing" - - "github.com/decred/dcrd/blockchain/stake/v3" ) -// TestErrorCodeStringer tests the stringized output for the ErrorCode type. -func TestErrorCodeStringer(t *testing.T) { +// TestErrorKindStringer tests the stringized output for the ErrorKind type. +func TestErrorKindStringer(t *testing.T) { tests := []struct { - in stake.ErrorCode + in ErrorKind want string }{ - {stake.ErrSStxTooManyInputs, "ErrSStxTooManyInputs"}, - {stake.ErrSStxTooManyOutputs, "ErrSStxTooManyOutputs"}, - {stake.ErrSStxNoOutputs, "ErrSStxNoOutputs"}, - {stake.ErrSStxInvalidInputs, "ErrSStxInvalidInputs"}, - {stake.ErrSStxInvalidOutputs, "ErrSStxInvalidOutputs"}, - {stake.ErrSStxInOutProportions, "ErrSStxInOutProportions"}, - {stake.ErrSStxBadCommitAmount, "ErrSStxBadCommitAmount"}, - {stake.ErrSStxBadChangeAmts, "ErrSStxBadChangeAmts"}, - {stake.ErrSStxVerifyCalcAmts, "ErrSStxVerifyCalcAmts"}, - {stake.ErrSSGenWrongNumInputs, "ErrSSGenWrongNumInputs"}, - {stake.ErrSSGenTooManyOutputs, "ErrSSGenTooManyOutputs"}, - {stake.ErrSSGenNoOutputs, "ErrSSGenNoOutputs"}, - {stake.ErrSSGenWrongIndex, "ErrSSGenWrongIndex"}, - {stake.ErrSSGenWrongTxTree, "ErrSSGenWrongTxTree"}, - {stake.ErrSSGenNoStakebase, "ErrSSGenNoStakebase"}, - {stake.ErrSSGenNoReference, "ErrSSGenNoReference"}, - {stake.ErrSSGenBadReference, "ErrSSGenBadReference"}, - {stake.ErrSSGenNoVotePush, "ErrSSGenNoVotePush"}, - {stake.ErrSSGenBadVotePush, "ErrSSGenBadVotePush"}, - {stake.ErrSSGenBadGenOuts, "ErrSSGenBadGenOuts"}, - {stake.ErrSSRtxWrongNumInputs, "ErrSSRtxWrongNumInputs"}, - {stake.ErrSSRtxTooManyOutputs, "ErrSSRtxTooManyOutputs"}, - {stake.ErrSSRtxNoOutputs, "ErrSSRtxNoOutputs"}, - {stake.ErrSSRtxWrongTxTree, "ErrSSRtxWrongTxTree"}, - {stake.ErrSSRtxBadOuts, "ErrSSRtxBadOuts"}, - {stake.ErrVerSStxAmts, "ErrVerSStxAmts"}, - {stake.ErrVerifyInput, "ErrVerifyInput"}, - {stake.ErrVerifyOutType, "ErrVerifyOutType"}, - {stake.ErrVerifyTooMuchFees, "ErrVerifyTooMuchFees"}, - {stake.ErrVerifySpendTooMuch, "ErrVerifySpendTooMuch"}, - {stake.ErrVerifyOutputAmt, "ErrVerifyOutputAmt"}, - {stake.ErrVerifyOutPkhs, "ErrVerifyOutPkhs"}, - {stake.ErrDatabaseCorrupt, "ErrDatabaseCorrupt"}, - {stake.ErrMissingDatabaseTx, "ErrMissingDatabaseTx"}, - {stake.ErrMemoryCorruption, "ErrMemoryCorruption"}, - {stake.ErrFindTicketIdxs, "ErrFindTicketIdxs"}, - {stake.ErrMissingTicket, "ErrMissingTicket"}, - {stake.ErrDuplicateTicket, "ErrDuplicateTicket"}, - {stake.ErrUnknownTicketSpent, "ErrUnknownTicketSpent"}, - {0xffff, "Unknown ErrorCode (65535)"}, + {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"}, } - t.Logf("Running %d tests", len(tests)) for i, test := range tests { - result := test.in.String() + result := test.in.Error() if result != test.want { - t.Errorf("String #%d\n got: %s want: %s", i, result, - test.want) + t.Errorf("%d: got: %s want: %s", i, result, test.want) continue } } @@ -73,23 +70,104 @@ func TestErrorCodeStringer(t *testing.T) { // TestRuleError tests the error output for the RuleError type. func TestRuleError(t *testing.T) { tests := []struct { - in stake.RuleError + in RuleError want string }{ - {stake.RuleError{Description: "duplicate block"}, + {RuleError{Description: "duplicate block"}, "duplicate block", }, - {stake.RuleError{Description: "human-readable error"}, + {RuleError{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) + t.Errorf("E%d: got: %s want: %s", i, result, test.want) + continue + } + } +} + +// TestErrorKindIsAs ensures both ErrorKind and Error can be identified as being +// a specific error kind via errors.Is and unwrapped via errors.As. +func TestErrorKindIsAs(t *testing.T) { + tests := []struct { + name string + err error + target error + wantMatch bool + wantAs ErrorKind + }{{ + name: "ErrSStxTooManyInputs == ErrSStxTooManyInputs", + err: ErrSStxTooManyInputs, + target: ErrSStxTooManyInputs, + wantMatch: true, + wantAs: ErrSStxTooManyInputs, + }, { + name: "Error.ErrSStxTooManyInputs == ErrSStxTooManyInputs", + err: stakeRuleError(ErrSStxTooManyInputs, ""), + target: ErrSStxTooManyInputs, + wantMatch: true, + wantAs: ErrSStxTooManyInputs, + }, { + name: "Error.ErrSStxTooManyInputs == Error.ErrSStxTooManyInputs", + err: stakeRuleError(ErrSStxTooManyInputs, ""), + target: stakeRuleError(ErrSStxTooManyInputs, ""), + wantMatch: true, + wantAs: ErrSStxTooManyInputs, + }, { + name: "ErrSStxTooManyInputs != ErrSSGenNoOutputs", + err: ErrSStxTooManyInputs, + target: ErrSSGenNoOutputs, + wantMatch: false, + wantAs: ErrSStxTooManyInputs, + }, { + name: "Error.ErrSStxTooManyInputs != ErrSSGenNoOutputs", + err: stakeRuleError(ErrSStxTooManyInputs, ""), + target: ErrSSGenNoOutputs, + wantMatch: false, + wantAs: ErrSStxTooManyInputs, + }, { + name: "ErrSStxTooManyInputs != Error.ErrSSGenNoOutputs", + err: ErrSStxTooManyInputs, + target: stakeRuleError(ErrSSGenNoOutputs, ""), + wantMatch: false, + wantAs: ErrSStxTooManyInputs, + }, { + name: "Error.ErrSStxTooManyInputs != Error.ErrSSGenNoOutputs", + err: stakeRuleError(ErrSStxTooManyInputs, ""), + target: stakeRuleError(ErrSSGenNoOutputs, ""), + wantMatch: false, + wantAs: ErrSStxTooManyInputs, + }, { + name: "Error.ErrDuplicateTicket != io.EOF", + err: stakeRuleError(ErrDuplicateTicket, ""), + target: io.EOF, + wantMatch: false, + wantAs: ErrDuplicateTicket, + }} + + for _, test := range tests { + // Ensure the error matches or not depending on the expected result. + result := errors.Is(test.err, test.target) + if result != test.wantMatch { + t.Errorf("%s: incorrect error identification -- got %v, want %v", + test.name, result, test.wantMatch) + continue + } + + // Ensure the underlying error kind can be unwrapped is and is the + // expected kind. + var kind ErrorKind + if !errors.As(test.err, &kind) { + t.Errorf("%s: unable to unwrap to error kind", test.name) + continue + } + if kind != test.wantAs { + t.Errorf("%s: unexpected unwrapped error kind -- got %v, want %v", + test.name, kind, test.wantAs) continue } } diff --git a/blockchain/stake/staketx.go b/blockchain/stake/staketx.go index 9542e75c07..98ef03556e 100644 --- a/blockchain/stake/staketx.go +++ b/blockchain/stake/staketx.go @@ -10,7 +10,6 @@ package stake import ( "bytes" "encoding/binary" - "errors" "fmt" "math" "math/big" @@ -395,8 +394,8 @@ func TxSStxStakeOutputInfo(tx *wire.MsgTx) ([]bool, [][]byte, []int64, []int64, // commitment pkScript. func AddrFromSStxPkScrCommitment(pkScript []byte, params dcrutil.AddressParams) (dcrutil.Address, error) { if len(pkScript) < SStxPKHMinOutSize { - return nil, stakeRuleError(ErrSStxBadCommitAmount, "short read "+ - "of sstx commit pkscript") + str := "short read of sstx commit pkscript" + return nil, stakeRuleError(ErrSStxBadCommitAmount, str) } // The MSB of the encoded amount specifies if the output is P2SH. Since @@ -425,8 +424,8 @@ func AddrFromSStxPkScrCommitment(pkScript []byte, params dcrutil.AddressParams) // ticket commitment pkScript. func AmountFromSStxPkScrCommitment(pkScript []byte) (dcrutil.Amount, error) { if len(pkScript) < SStxPKHMinOutSize { - return 0, stakeRuleError(ErrSStxBadCommitAmount, "short read "+ - "of sstx commit pkscript") + str := "short read of sstx commit pkscript" + return 0, stakeRuleError(ErrSStxBadCommitAmount, str) } // The MSB (sign), not used ever normally, encodes whether @@ -491,14 +490,13 @@ func SStxNullOutputAmounts(amounts []int64, lengthAmounts := len(amounts) if lengthAmounts != len(changeAmounts) { - errStr := fmt.Sprintf("amounts was not equal in length " + - "to change amounts!") - return 0, nil, errors.New(errStr) + str := "amounts was not equal in length to change amounts!" + return 0, nil, fmt.Errorf(str) } if amountTicket <= 0 { - errStr := "committed amount was too small!" - return 0, nil, stakeRuleError(ErrSStxBadCommitAmount, errStr) + str := "committed amount was too small!" + return 0, nil, stakeRuleError(ErrSStxBadCommitAmount, str) } contribAmounts := make([]int64, lengthAmounts) @@ -512,9 +510,9 @@ func SStxNullOutputAmounts(amounts []int64, for i := 0; i < lengthAmounts; i++ { contribAmounts[i] = amounts[i] - changeAmounts[i] if contribAmounts[i] < 0 { - errStr := fmt.Sprintf("change at idx %v spent more coins than "+ + str := fmt.Sprintf("change at idx %v spent more coins than "+ "allowed (have: %v, spent: %v)", i, amounts[i], changeAmounts[i]) - return 0, nil, stakeRuleError(ErrSStxBadChangeAmts, errStr) + return 0, nil, stakeRuleError(ErrSStxBadChangeAmts, str) } sum += contribAmounts[i] @@ -607,42 +605,44 @@ func CheckSStx(tx *wire.MsgTx) error { // CheckTransactionSanity already makes sure that number of inputs is // greater than 0, so no need to check that. if len(tx.TxIn) > MaxInputsPerSStx { - return stakeRuleError(ErrSStxTooManyInputs, "SStx has too many "+ - "inputs") + str := "SStx has too many inputs" + return stakeRuleError(ErrSStxTooManyInputs, str) } // Check to make sure there aren't too many outputs. if len(tx.TxOut) > MaxOutputsPerSStx { - return stakeRuleError(ErrSStxTooManyOutputs, "SStx has too many "+ - "outputs") + str := "SStx has too many outputs" + return stakeRuleError(ErrSStxTooManyOutputs, str) } // Check to make sure there are some outputs. if len(tx.TxOut) == 0 { - return stakeRuleError(ErrSStxNoOutputs, "SStx has no "+ - "outputs") + str := "SStx has no outputs" + return stakeRuleError(ErrSStxNoOutputs, str) } // Check to make sure that all output scripts are the consensus version. for idx, txOut := range tx.TxOut { if txOut.Version != consensusVersion { - errStr := fmt.Sprintf("invalid script version found in "+ + str := fmt.Sprintf("invalid script version found in "+ "txOut idx %v", idx) - return stakeRuleError(ErrSStxInvalidOutputs, errStr) + return stakeRuleError(ErrSStxInvalidOutputs, str) } } // Ensure that the first output is tagged OP_SSTX. if !IsTicketPurchaseScript(tx.TxOut[0].Version, tx.TxOut[0].PkScript) { - return stakeRuleError(ErrSStxInvalidOutputs, "First SStx output "+ - "should have been OP_SSTX tagged, but it was not") + str := "first SStx output should have been OP_SSTX tagged, " + + "but it was not" + return stakeRuleError(ErrSStxInvalidOutputs, str) } // Ensure that the number of outputs is equal to the number of inputs // + 1. if (len(tx.TxIn)*2 + 1) != len(tx.TxOut) { - return stakeRuleError(ErrSStxInOutProportions, "The number of "+ - "inputs in the SStx tx was not the number of outputs/2 - 1") + str := "the number of inputs in the SStx tx was not the number " + + "of outputs/2 - 1" + return stakeRuleError(ErrSStxInOutProportions, str) } // Ensure that the rest of the odd outputs are 28-byte OP_RETURN pushes that @@ -691,10 +691,9 @@ func CheckSStx(tx *wire.MsgTx) error { // valid push length. if !(outputScriptPrefix[0] == validSStxAddressOutMinPrefix[0]) || !pushLengthValid { - errStr := fmt.Sprintf("sstx commitment at output idx %v had "+ + str := fmt.Sprintf("sstx commitment at output idx %v had "+ "an invalid prefix", outTxIndex) - return stakeRuleError(ErrSStxInvalidOutputs, - errStr) + return stakeRuleError(ErrSStxInvalidOutputs, str) } } @@ -737,27 +736,28 @@ func CheckSSGen(tx *wire.MsgTx) error { // CheckTransactionSanity already makes sure that number of inputs is // greater than 0, so no need to check that. if len(tx.TxIn) != NumInputsPerSSGen { - return stakeRuleError(ErrSSGenWrongNumInputs, "SSgen tx has an "+ - "invalid number of inputs") + str := "SSgen tx has an invalid number of inputs" + return stakeRuleError(ErrSSGenWrongNumInputs, str) } // Check to make sure there aren't too many outputs. if len(tx.TxOut) > MaxOutputsPerSSGen { - return stakeRuleError(ErrSSGenTooManyOutputs, "SSgen tx has too "+ - "many outputs") + str := "SSgen tx has too many outputs" + return stakeRuleError(ErrSSGenTooManyOutputs, str) } // Check to make sure there are enough outputs. if len(tx.TxOut) < 2 { - return stakeRuleError(ErrSSGenNoOutputs, "SSgen tx does not "+ - "have enough outputs") + str := "SSgen tx does not have enough outputs" + return stakeRuleError(ErrSSGenNoOutputs, str) } // Ensure that the first input is a stake base null input. // Also checks to make sure that there aren't too many or too few inputs. if !IsStakeBase(tx) { - return stakeRuleError(ErrSSGenNoStakebase, "SSGen tx did not "+ - "include a stakebase in the zeroeth input position") + str := "SSGen tx did not include a stakebase in the zeroeth " + + "input position" + return stakeRuleError(ErrSSGenNoStakebase, str) } // Check to make sure that the output used as input came from TxTreeStake. @@ -768,22 +768,22 @@ func CheckSSGen(tx *wire.MsgTx) error { } if txin.PreviousOutPoint.Index != 0 { - errStr := fmt.Sprintf("SSGen used an invalid input idx (got %v, "+ + str := fmt.Sprintf("SSGen used an invalid input idx (got %v, "+ "want 0)", txin.PreviousOutPoint.Index) - return stakeRuleError(ErrSSGenWrongIndex, errStr) + return stakeRuleError(ErrSSGenWrongIndex, str) } if txin.PreviousOutPoint.Tree != wire.TxTreeStake { - return stakeRuleError(ErrSSGenWrongTxTree, "SSGen used "+ - "a non-stake input") + str := "SSGen used a non-stake input" + return stakeRuleError(ErrSSGenWrongTxTree, str) } } // Check to make sure that all output scripts are the consensus version. for _, txOut := range tx.TxOut { if txOut.Version != consensusVersion { - return stakeRuleError(ErrSSGenBadGenOuts, "invalid "+ - "script version found in txOut") + str := "invalid script version found in txOut" + return stakeRuleError(ErrSSGenBadGenOuts, str) } } @@ -799,14 +799,15 @@ func CheckSSGen(tx *wire.MsgTx) error { zeroethOutputVersion := tx.TxOut[0].Version zeroethOutputScript := tx.TxOut[0].PkScript if !IsNullDataScript(zeroethOutputVersion, zeroethOutputScript) { - return stakeRuleError(ErrSSGenNoReference, "First SSGen output "+ - "should have been an OP_RETURN data push, but was not") + str := "first SSGen output should have been an OP_RETURN " + + "data push, but was not" + return stakeRuleError(ErrSSGenNoReference, str) } // Ensure that the first output is the correct size. if len(zeroethOutputScript) != SSGenBlockReferenceOutSize { - return stakeRuleError(ErrSSGenBadReference, "First SSGen output "+ - "should have been 43 bytes long, but was not") + str := "first SSGen output should have been 43 bytes long, but was not" + return stakeRuleError(ErrSSGenBadReference, str) } // The OP_RETURN output script prefix for block referencing should @@ -816,8 +817,8 @@ func CheckSSGen(tx *wire.MsgTx) error { zeroethOutputScriptPrefix := zeroethOutputScriptBuffer.Next(2) if !bytes.Equal(zeroethOutputScriptPrefix, validSSGenReferenceOutPrefix) { - return stakeRuleError(ErrSSGenBadReference, "First SSGen output "+ - "had an invalid prefix") + str := "first SSGen output had an invalid prefix" + return stakeRuleError(ErrSSGenBadReference, str) } // Ensure that the block header hash given in the first 32 bytes of the @@ -828,8 +829,9 @@ func CheckSSGen(tx *wire.MsgTx) error { firstOutputVersion := tx.TxOut[1].Version firstOutputScript := tx.TxOut[1].PkScript if !IsNullDataScript(firstOutputVersion, firstOutputScript) { - return stakeRuleError(ErrSSGenNoVotePush, "Second SSGen output "+ - "should have been an OP_RETURN data push, but was not") + str := "second SSGen output should have been an OP_RETURN " + + "data push, but was not" + return stakeRuleError(ErrSSGenNoVotePush, str) } // The length of the output script should be between 4 and 77 bytes long. @@ -854,8 +856,8 @@ func CheckSSGen(tx *wire.MsgTx) error { // valid push length. if !(firstOutputScriptPrefix[0] == validSSGenVoteOutMinPrefix[0]) || !pushLengthValid { - return stakeRuleError(ErrSSGenBadVotePush, "Second SSGen output "+ - "had an invalid prefix") + str := "second SSGen output had an invalid prefix" + return stakeRuleError(ErrSSGenBadVotePush, str) } // Ensure that the tx height given in the last 8 bytes is StakeMaturity @@ -907,35 +909,35 @@ func CheckSSRtx(tx *wire.MsgTx) error { // CheckTransactionSanity already makes sure that number of inputs is // greater than 0, so no need to check that. if len(tx.TxIn) != NumInputsPerSSRtx { - return stakeRuleError(ErrSSRtxWrongNumInputs, "SSRtx has an "+ - " invalid number of inputs") + str := "SSRtx has an invalid number of inputs" + return stakeRuleError(ErrSSRtxWrongNumInputs, str) } // Check to make sure there aren't too many outputs. if len(tx.TxOut) > MaxOutputsPerSSRtx { - return stakeRuleError(ErrSSRtxTooManyOutputs, "SSRtx has too "+ - "many outputs") + str := "SSRtx has too many outputs" + return stakeRuleError(ErrSSRtxTooManyOutputs, str) } // Check to make sure there are some outputs. if len(tx.TxOut) == 0 { - return stakeRuleError(ErrSSRtxNoOutputs, "SSRtx has no "+ - "outputs") + str := "SSRtx has no outputs" + return stakeRuleError(ErrSSRtxNoOutputs, str) } // Check to make sure that all output scripts are the consensus version. for _, txOut := range tx.TxOut { if txOut.Version != consensusVersion { - return stakeRuleError(ErrSSRtxBadOuts, "invalid "+ - "script version found in txOut") + str := "invalid script version found in txOut" + return stakeRuleError(ErrSSRtxBadOuts, str) } } // Check to make sure that the output used as input came from TxTreeStake. for _, txin := range tx.TxIn { if txin.PreviousOutPoint.Tree != wire.TxTreeStake { - return stakeRuleError(ErrSSRtxWrongTxTree, "SSRtx used "+ - "a non-stake input") + str := "SSRtx used a non-stake input" + return stakeRuleError(ErrSSRtxWrongTxTree, str) } } diff --git a/blockchain/stake/staketx_test.go b/blockchain/stake/staketx_test.go index 87863ecfe7..1e1c5e985e 100644 --- a/blockchain/stake/staketx_test.go +++ b/blockchain/stake/staketx_test.go @@ -2,7 +2,7 @@ // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. -package stake_test +package stake import ( "bytes" @@ -11,7 +11,6 @@ import ( "reflect" "testing" - "github.com/decred/dcrd/blockchain/stake/v3" "github.com/decred/dcrd/chaincfg/chainhash" "github.com/decred/dcrd/dcrutil/v3" "github.com/decred/dcrd/txscript/v3" @@ -27,11 +26,11 @@ func TestSStx(t *testing.T) { sstx.SetTree(wire.TxTreeStake) sstx.SetIndex(0) - err := stake.CheckSStx(sstx.MsgTx()) + err := CheckSStx(sstx.MsgTx()) if err != nil { t.Errorf("CheckSStx: unexpected err: %v", err) } - if !stake.IsSStx(sstx.MsgTx()) { + if !IsSStx(sstx.MsgTx()) { t.Errorf("IsSStx claimed a valid sstx is invalid") } @@ -56,11 +55,11 @@ func TestSStx(t *testing.T) { sstx.SetTree(wire.TxTreeStake) sstx.SetIndex(0) - err = stake.CheckSStx(sstx.MsgTx()) + err = CheckSStx(sstx.MsgTx()) if err != nil { t.Errorf("CheckSStx: unexpected err: %v", err) } - if !stake.IsSStx(sstx.MsgTx()) { + if !IsSStx(sstx.MsgTx()) { t.Errorf("IsSStx claimed a valid sstx is invalid") } } @@ -84,13 +83,13 @@ func TestSSTxErrors(t *testing.T) { sstxExtraInputs.SetTree(wire.TxTreeStake) sstxExtraInputs.SetIndex(0) - var serr stake.RuleError - err = stake.CheckSStx(sstxExtraInputs.MsgTx()) - if !errors.As(err, &serr) || serr.GetCode() != stake.ErrSStxTooManyInputs { + var serr RuleError + err = CheckSStx(sstxExtraInputs.MsgTx()) + if !errors.As(err, &serr) || !errors.Is(serr, ErrSStxTooManyInputs) { t.Errorf("CheckSStx should have returned %v but instead returned %v", - stake.ErrSStxTooManyInputs, err) + ErrSStxTooManyInputs, err) } - if stake.IsSStx(sstxExtraInputs.MsgTx()) { + if IsSStx(sstxExtraInputs.MsgTx()) { t.Errorf("IsSStx claimed an invalid sstx is valid") } @@ -101,12 +100,12 @@ func TestSSTxErrors(t *testing.T) { sstxExtraOutputs.SetTree(wire.TxTreeStake) sstxExtraOutputs.SetIndex(0) - err = stake.CheckSStx(sstxExtraOutputs.MsgTx()) - if !errors.As(err, &serr) || serr.GetCode() != stake.ErrSStxTooManyOutputs { + err = CheckSStx(sstxExtraOutputs.MsgTx()) + if !errors.As(err, &serr) || !errors.Is(serr, ErrSStxTooManyOutputs) { t.Errorf("CheckSStx should have returned %v but instead returned %v", - stake.ErrSStxTooManyOutputs, err) + ErrSStxTooManyOutputs, err) } - if stake.IsSStx(sstxExtraOutputs.MsgTx()) { + if IsSStx(sstxExtraOutputs.MsgTx()) { t.Errorf("IsSStx claimed an invalid sstx is valid") } @@ -132,12 +131,12 @@ func TestSSTxErrors(t *testing.T) { sstxUntaggedOut.SetTree(wire.TxTreeStake) sstxUntaggedOut.SetIndex(0) - err = stake.CheckSStx(sstxUntaggedOut.MsgTx()) - if !errors.As(err, &serr) || serr.GetCode() != stake.ErrSStxInvalidOutputs { + err = CheckSStx(sstxUntaggedOut.MsgTx()) + if !errors.As(err, &serr) || !errors.Is(serr, ErrSStxInvalidOutputs) { t.Errorf("CheckSStx should have returned %v but instead returned %v", - stake.ErrSStxInvalidOutputs, err) + ErrSStxInvalidOutputs, err) } - if stake.IsSStx(sstxUntaggedOut.MsgTx()) { + if IsSStx(sstxUntaggedOut.MsgTx()) { t.Errorf("IsSStx claimed an invalid sstx is valid") } @@ -148,12 +147,12 @@ func TestSSTxErrors(t *testing.T) { sstxInsOutsMismatched.SetTree(wire.TxTreeStake) sstxInsOutsMismatched.SetIndex(0) - err = stake.CheckSStx(sstxInsOutsMismatched.MsgTx()) - if !errors.As(err, &serr) || serr.GetCode() != stake.ErrSStxInOutProportions { + err = CheckSStx(sstxInsOutsMismatched.MsgTx()) + if !errors.As(err, &serr) || !errors.Is(serr, ErrSStxInOutProportions) { t.Errorf("CheckSStx should have returned %v but instead returned %v", - stake.ErrSStxInOutProportions, err) + ErrSStxInOutProportions, err) } - if stake.IsSStx(sstxInsOutsMismatched.MsgTx()) { + if IsSStx(sstxInsOutsMismatched.MsgTx()) { t.Errorf("IsSStx claimed an invalid sstx is valid") } @@ -163,12 +162,12 @@ func TestSSTxErrors(t *testing.T) { sstxBadVerOut.SetTree(wire.TxTreeStake) sstxBadVerOut.SetIndex(0) - err = stake.CheckSStx(sstxBadVerOut.MsgTx()) - if !errors.As(err, &serr) || serr.GetCode() != stake.ErrSStxInvalidOutputs { + err = CheckSStx(sstxBadVerOut.MsgTx()) + if !errors.As(err, &serr) || !errors.Is(serr, ErrSStxInvalidOutputs) { t.Errorf("CheckSStx should have returned %v but instead returned %v", - stake.ErrSStxInvalidOutputs, err) + ErrSStxInvalidOutputs, err) } - if stake.IsSStx(sstxBadVerOut.MsgTx()) { + if IsSStx(sstxBadVerOut.MsgTx()) { t.Errorf("IsSStx claimed an invalid sstx is valid") } @@ -179,12 +178,12 @@ func TestSSTxErrors(t *testing.T) { sstxNoNullData.SetTree(wire.TxTreeStake) sstxNoNullData.SetIndex(0) - err = stake.CheckSStx(sstxNoNullData.MsgTx()) - if !errors.As(err, &serr) || serr.GetCode() != stake.ErrSStxInvalidOutputs { + err = CheckSStx(sstxNoNullData.MsgTx()) + if !errors.As(err, &serr) || !errors.Is(serr, ErrSStxInvalidOutputs) { t.Errorf("CheckSStx should have returned %v but instead returned %v", - stake.ErrSStxInvalidOutputs, err) + ErrSStxInvalidOutputs, err) } - if stake.IsSStx(sstxNoNullData.MsgTx()) { + if IsSStx(sstxNoNullData.MsgTx()) { t.Errorf("IsSStx claimed an invalid sstx is valid") } @@ -195,12 +194,12 @@ func TestSSTxErrors(t *testing.T) { sstxNullDataMis.SetTree(wire.TxTreeStake) sstxNullDataMis.SetIndex(0) - err = stake.CheckSStx(sstxNullDataMis.MsgTx()) - if !errors.As(err, &serr) || serr.GetCode() != stake.ErrSStxInvalidOutputs { + err = CheckSStx(sstxNullDataMis.MsgTx()) + if !errors.As(err, &serr) || !errors.Is(serr, ErrSStxInvalidOutputs) { t.Errorf("CheckSStx should have returned %v but instead returned %v", - stake.ErrSStxInvalidOutputs, err) + ErrSStxInvalidOutputs, err) } - if stake.IsSStx(sstxNullDataMis.MsgTx()) { + if IsSStx(sstxNullDataMis.MsgTx()) { t.Errorf("IsSStx claimed an invalid sstx is valid") } @@ -231,12 +230,12 @@ func TestSSTxErrors(t *testing.T) { sstxWrongPKHLength.SetTree(wire.TxTreeStake) sstxWrongPKHLength.SetIndex(0) - err = stake.CheckSStx(sstxWrongPKHLength.MsgTx()) - if !errors.As(err, &serr) || serr.GetCode() != stake.ErrSStxInvalidOutputs { + err = CheckSStx(sstxWrongPKHLength.MsgTx()) + if !errors.As(err, &serr) || !errors.Is(serr, ErrSStxInvalidOutputs) { t.Errorf("CheckSStx should have returned %v but instead returned %v", - stake.ErrSStxInvalidOutputs, err) + ErrSStxInvalidOutputs, err) } - if stake.IsSStx(sstxWrongPKHLength.MsgTx()) { + if IsSStx(sstxWrongPKHLength.MsgTx()) { t.Errorf("IsSStx claimed an invalid sstx is valid") } @@ -268,12 +267,12 @@ func TestSSTxErrors(t *testing.T) { sstxWrongPrefix.SetTree(wire.TxTreeStake) sstxWrongPrefix.SetIndex(0) - err = stake.CheckSStx(sstxWrongPrefix.MsgTx()) - if !errors.As(err, &serr) || serr.GetCode() != stake.ErrSStxInvalidOutputs { + err = CheckSStx(sstxWrongPrefix.MsgTx()) + if !errors.As(err, &serr) || !errors.Is(serr, ErrSStxInvalidOutputs) { t.Errorf("CheckSStx should have returned %v but instead returned %v", - stake.ErrSStxInvalidOutputs, err) + ErrSStxInvalidOutputs, err) } - if stake.IsSStx(sstxWrongPrefix.MsgTx()) { + if IsSStx(sstxWrongPrefix.MsgTx()) { t.Errorf("IsSStx claimed an invalid sstx is valid") } } @@ -287,11 +286,11 @@ func TestSSGen(t *testing.T) { ssgen.SetTree(wire.TxTreeStake) ssgen.SetIndex(0) - err := stake.CheckSSGen(ssgen.MsgTx()) + err := CheckSSGen(ssgen.MsgTx()) if err != nil { t.Errorf("IsSSGen: unexpected err: %v", err) } - if !stake.IsSSGen(ssgen.MsgTx()) { + if !IsSSGen(ssgen.MsgTx()) { t.Errorf("IsSSGen claimed a valid ssgen is invalid") } @@ -315,11 +314,11 @@ func TestSSGen(t *testing.T) { ssgen.SetIndex(0) ssgen.MsgTx().TxOut[1].PkScript = biggestPush - err = stake.CheckSSGen(ssgen.MsgTx()) + err = CheckSSGen(ssgen.MsgTx()) if err != nil { t.Errorf("IsSSGen: unexpected err: %v", err) } - if !stake.IsSSGen(ssgen.MsgTx()) { + if !IsSSGen(ssgen.MsgTx()) { t.Errorf("IsSSGen claimed a valid ssgen is invalid") } } @@ -344,13 +343,13 @@ func TestSSGenErrors(t *testing.T) { ssgenExtraInputs.SetTree(wire.TxTreeStake) ssgenExtraInputs.SetIndex(0) - var serr stake.RuleError - err = stake.CheckSSGen(ssgenExtraInputs.MsgTx()) - if !errors.As(err, &serr) || serr.GetCode() != stake.ErrSSGenWrongNumInputs { + var serr RuleError + err = CheckSSGen(ssgenExtraInputs.MsgTx()) + if !errors.As(err, &serr) || !errors.Is(serr, ErrSSGenWrongNumInputs) { t.Errorf("CheckSSGen should have returned %v but instead returned %v", - stake.ErrSSGenWrongNumInputs, err) + ErrSSGenWrongNumInputs, err) } - if stake.IsSSGen(ssgenExtraInputs.MsgTx()) { + if IsSSGen(ssgenExtraInputs.MsgTx()) { t.Errorf("IsSSGen claimed an invalid ssgen is valid") } @@ -361,12 +360,12 @@ func TestSSGenErrors(t *testing.T) { ssgenExtraOutputs.SetTree(wire.TxTreeStake) ssgenExtraOutputs.SetIndex(0) - err = stake.CheckSSGen(ssgenExtraOutputs.MsgTx()) - if !errors.As(err, &serr) || serr.GetCode() != stake.ErrSSGenTooManyOutputs { + err = CheckSSGen(ssgenExtraOutputs.MsgTx()) + if !errors.As(err, &serr) || !errors.Is(serr, ErrSSGenTooManyOutputs) { t.Errorf("CheckSSGen should have returned %v but instead returned %v", - stake.ErrSSGenTooManyOutputs, err) + ErrSSGenTooManyOutputs, err) } - if stake.IsSSGen(ssgenExtraOutputs.MsgTx()) { + if IsSSGen(ssgenExtraOutputs.MsgTx()) { t.Errorf("IsSSGen claimed an invalid ssgen is valid") } @@ -377,12 +376,12 @@ func TestSSGenErrors(t *testing.T) { ssgenStakeBaseWrong.SetTree(wire.TxTreeStake) ssgenStakeBaseWrong.SetIndex(0) - err = stake.CheckSSGen(ssgenStakeBaseWrong.MsgTx()) - if !errors.As(err, &serr) || serr.GetCode() != stake.ErrSSGenNoStakebase { + err = CheckSSGen(ssgenStakeBaseWrong.MsgTx()) + if !errors.As(err, &serr) || !errors.Is(serr, ErrSSGenNoStakebase) { t.Errorf("CheckSSGen should have returned %v but instead returned %v", - stake.ErrSSGenNoStakebase, err) + ErrSSGenNoStakebase, err) } - if stake.IsSSGen(ssgenStakeBaseWrong.MsgTx()) { + if IsSSGen(ssgenStakeBaseWrong.MsgTx()) { t.Errorf("IsSSGen claimed an invalid ssgen is valid") } @@ -409,12 +408,12 @@ func TestSSGenErrors(t *testing.T) { ssgenWrongTreeIns.SetTree(wire.TxTreeStake) ssgenWrongTreeIns.SetIndex(0) - err = stake.CheckSSGen(ssgenWrongTreeIns.MsgTx()) - if !errors.As(err, &serr) || serr.GetCode() != stake.ErrSSGenWrongTxTree { + err = CheckSSGen(ssgenWrongTreeIns.MsgTx()) + if !errors.As(err, &serr) || !errors.Is(serr, ErrSSGenWrongTxTree) { t.Errorf("CheckSSGen should have returned %v but instead returned %v", - stake.ErrSSGenWrongTxTree, err) + ErrSSGenWrongTxTree, err) } - if stake.IsSSGen(ssgenWrongTreeIns.MsgTx()) { + if IsSSGen(ssgenWrongTreeIns.MsgTx()) { t.Errorf("IsSSGen claimed an invalid ssgen is valid") } @@ -424,12 +423,12 @@ func TestSSGenErrors(t *testing.T) { ssgenTxBadVerOut.SetTree(wire.TxTreeStake) ssgenTxBadVerOut.SetIndex(0) - err = stake.CheckSSGen(ssgenTxBadVerOut.MsgTx()) - if !errors.As(err, &serr) || serr.GetCode() != stake.ErrSSGenBadGenOuts { + err = CheckSSGen(ssgenTxBadVerOut.MsgTx()) + if !errors.As(err, &serr) || !errors.Is(serr, ErrSSGenBadGenOuts) { t.Errorf("CheckSSGen should have returned %v but instead returned %v", - stake.ErrSSGenBadGenOuts, err) + ErrSSGenBadGenOuts, err) } - if stake.IsSSGen(ssgenTxBadVerOut.MsgTx()) { + if IsSSGen(ssgenTxBadVerOut.MsgTx()) { t.Errorf("IsSSGen claimed an invalid ssgen is valid") } @@ -440,12 +439,12 @@ func TestSSGenErrors(t *testing.T) { ssgenWrongZeroethOut.SetTree(wire.TxTreeStake) ssgenWrongZeroethOut.SetIndex(0) - err = stake.CheckSSGen(ssgenWrongZeroethOut.MsgTx()) - if !errors.As(err, &serr) || serr.GetCode() != stake.ErrSSGenNoReference { + err = CheckSSGen(ssgenWrongZeroethOut.MsgTx()) + if !errors.As(err, &serr) || !errors.Is(serr, ErrSSGenNoReference) { t.Errorf("CheckSSGen should have returned %v but instead returned %v", - stake.ErrSSGenNoReference, err) + ErrSSGenNoReference, err) } - if stake.IsSSGen(ssgenWrongZeroethOut.MsgTx()) { + if IsSSGen(ssgenWrongZeroethOut.MsgTx()) { t.Errorf("IsSSGen claimed an invalid ssgen is valid") } @@ -482,12 +481,12 @@ func TestSSGenErrors(t *testing.T) { ssgenWrongDataPush0Length.SetTree(wire.TxTreeStake) ssgenWrongDataPush0Length.SetIndex(0) - err = stake.CheckSSGen(ssgenWrongDataPush0Length.MsgTx()) - if !errors.As(err, &serr) || serr.GetCode() != stake.ErrSSGenBadReference { + err = CheckSSGen(ssgenWrongDataPush0Length.MsgTx()) + if !errors.As(err, &serr) || !errors.Is(serr, ErrSSGenBadReference) { t.Errorf("CheckSSGen should have returned %v but instead returned %v", - stake.ErrSSGenBadReference, err) + ErrSSGenBadReference, err) } - if stake.IsSSGen(ssgenWrongDataPush0Length.MsgTx()) { + if IsSSGen(ssgenWrongDataPush0Length.MsgTx()) { t.Errorf("IsSSGen claimed an invalid ssgen is valid") } @@ -524,12 +523,12 @@ func TestSSGenErrors(t *testing.T) { ssgenWrongNullData0Prefix.SetTree(wire.TxTreeStake) ssgenWrongNullData0Prefix.SetIndex(0) - err = stake.CheckSSGen(ssgenWrongNullData0Prefix.MsgTx()) - if !errors.As(err, &serr) || serr.GetCode() != stake.ErrSSGenBadReference { + err = CheckSSGen(ssgenWrongNullData0Prefix.MsgTx()) + if !errors.As(err, &serr) || !errors.Is(serr, ErrSSGenBadReference) { t.Errorf("CheckSSGen should have returned %v but instead returned %v", - stake.ErrSSGenBadReference, err) + ErrSSGenBadReference, err) } - if stake.IsSSGen(ssgenWrongNullData0Prefix.MsgTx()) { + if IsSSGen(ssgenWrongNullData0Prefix.MsgTx()) { t.Errorf("IsSSGen claimed an invalid ssgen is valid") } @@ -540,12 +539,12 @@ func TestSSGenErrors(t *testing.T) { ssgenWrongFirstOut.SetTree(wire.TxTreeStake) ssgenWrongFirstOut.SetIndex(0) - err = stake.CheckSSGen(ssgenWrongFirstOut.MsgTx()) - if !errors.As(err, &serr) || serr.GetCode() != stake.ErrSSGenNoVotePush { + err = CheckSSGen(ssgenWrongFirstOut.MsgTx()) + if !errors.As(err, &serr) || !errors.Is(serr, ErrSSGenNoVotePush) { t.Errorf("CheckSSGen should have returned %v but instead returned %v", - stake.ErrSSGenNoVotePush, err) + ErrSSGenNoVotePush, err) } - if stake.IsSSGen(ssgenWrongFirstOut.MsgTx()) { + if IsSSGen(ssgenWrongFirstOut.MsgTx()) { t.Errorf("IsSSGen claimed an invalid ssgen is valid") } @@ -571,12 +570,12 @@ func TestSSGenErrors(t *testing.T) { ssgenWrongDataPush1Length.SetTree(wire.TxTreeStake) ssgenWrongDataPush1Length.SetIndex(0) - err = stake.CheckSSGen(ssgenWrongDataPush1Length.MsgTx()) - if !errors.As(err, &serr) || serr.GetCode() != stake.ErrSSGenBadVotePush { + err = CheckSSGen(ssgenWrongDataPush1Length.MsgTx()) + if !errors.As(err, &serr) || !errors.Is(serr, ErrSSGenBadVotePush) { t.Errorf("CheckSSGen should have returned %v but instead returned %v", - stake.ErrSSGenBadVotePush, err) + ErrSSGenBadVotePush, err) } - if stake.IsSSGen(ssgenWrongDataPush1Length.MsgTx()) { + if IsSSGen(ssgenWrongDataPush1Length.MsgTx()) { t.Errorf("IsSSGen claimed an invalid ssgen is valid") } @@ -603,12 +602,12 @@ func TestSSGenErrors(t *testing.T) { ssgenWrongNullData1Prefix.SetTree(wire.TxTreeStake) ssgenWrongNullData1Prefix.SetIndex(0) - err = stake.CheckSSGen(ssgenWrongNullData1Prefix.MsgTx()) - if !errors.As(err, &serr) || serr.GetCode() != stake.ErrSSGenBadVotePush { + err = CheckSSGen(ssgenWrongNullData1Prefix.MsgTx()) + if !errors.As(err, &serr) || !errors.Is(serr, ErrSSGenBadVotePush) { t.Errorf("CheckSSGen should have returned %v but instead returned %v", - stake.ErrSSGenBadVotePush, err) + ErrSSGenBadVotePush, err) } - if stake.IsSSGen(ssgenWrongNullData1Prefix.MsgTx()) { + if IsSSGen(ssgenWrongNullData1Prefix.MsgTx()) { t.Errorf("IsSSGen claimed an invalid ssgen is valid") } @@ -635,12 +634,12 @@ func TestSSGenErrors(t *testing.T) { ssgentestGenOutputUntagged.SetTree(wire.TxTreeStake) ssgentestGenOutputUntagged.SetIndex(0) - err = stake.CheckSSGen(ssgentestGenOutputUntagged.MsgTx()) - if !errors.As(err, &serr) || serr.GetCode() != stake.ErrSSGenBadGenOuts { + err = CheckSSGen(ssgentestGenOutputUntagged.MsgTx()) + if !errors.As(err, &serr) || !errors.Is(serr, ErrSSGenBadGenOuts) { t.Errorf("CheckSSGen should have returned %v but instead returned %v", - stake.ErrSSGenBadGenOuts, err) + ErrSSGenBadGenOuts, err) } - if stake.IsSSGen(ssgentestGenOutputUntagged.MsgTx()) { + if IsSSGen(ssgentestGenOutputUntagged.MsgTx()) { t.Errorf("IsSSGen claimed an invalid ssgen is valid") } } @@ -654,11 +653,11 @@ func TestSSRtx(t *testing.T) { ssrtx.SetTree(wire.TxTreeStake) ssrtx.SetIndex(0) - err := stake.CheckSSRtx(ssrtx.MsgTx()) + err := CheckSSRtx(ssrtx.MsgTx()) if err != nil { t.Errorf("IsSSRtx: unexpected err: %v", err) } - if !stake.IsSSRtx(ssrtx.MsgTx()) { + if !IsSSRtx(ssrtx.MsgTx()) { t.Errorf("IsSSRtx claimed a valid ssrtx is invalid") } } @@ -683,13 +682,13 @@ func TestIsSSRtxErrors(t *testing.T) { ssrtxTooManyInputs.SetTree(wire.TxTreeStake) ssrtxTooManyInputs.SetIndex(0) - var serr stake.RuleError - err = stake.CheckSSRtx(ssrtxTooManyInputs.MsgTx()) - if !errors.As(err, &serr) || serr.GetCode() != stake.ErrSSRtxWrongNumInputs { + var serr RuleError + err = CheckSSRtx(ssrtxTooManyInputs.MsgTx()) + if !errors.As(err, &serr) || !errors.Is(serr, ErrSSRtxWrongNumInputs) { t.Errorf("CheckSSRtx should have returned %v but instead returned %v", - stake.ErrSSRtxWrongNumInputs, err) + ErrSSRtxWrongNumInputs, err) } - if stake.IsSSRtx(ssrtxTooManyInputs.MsgTx()) { + if IsSSRtx(ssrtxTooManyInputs.MsgTx()) { t.Errorf("IsSSRtx claimed an invalid ssrtx is valid") } @@ -700,12 +699,12 @@ func TestIsSSRtxErrors(t *testing.T) { ssrtxTooManyOutputs.SetTree(wire.TxTreeStake) ssrtxTooManyOutputs.SetIndex(0) - err = stake.CheckSSRtx(ssrtxTooManyOutputs.MsgTx()) - if !errors.As(err, &serr) || serr.GetCode() != stake.ErrSSRtxTooManyOutputs { + err = CheckSSRtx(ssrtxTooManyOutputs.MsgTx()) + if !errors.As(err, &serr) || !errors.Is(serr, ErrSSRtxTooManyOutputs) { t.Errorf("CheckSSRtx should have returned %v but instead returned %v", - stake.ErrSSRtxTooManyOutputs, err) + ErrSSRtxTooManyOutputs, err) } - if stake.IsSSRtx(ssrtxTooManyOutputs.MsgTx()) { + if IsSSRtx(ssrtxTooManyOutputs.MsgTx()) { t.Errorf("IsSSRtx claimed an invalid ssrtx is valid") } @@ -715,12 +714,12 @@ func TestIsSSRtxErrors(t *testing.T) { ssrtxTxBadVerOut.SetTree(wire.TxTreeStake) ssrtxTxBadVerOut.SetIndex(0) - err = stake.CheckSSRtx(ssrtxTxBadVerOut.MsgTx()) - if !errors.As(err, &serr) || serr.GetCode() != stake.ErrSSRtxBadOuts { + err = CheckSSRtx(ssrtxTxBadVerOut.MsgTx()) + if !errors.As(err, &serr) || !errors.Is(serr, ErrSSRtxBadOuts) { t.Errorf("CheckSSRtx should have returned %v but instead returned %v", - stake.ErrSSRtxBadOuts, err) + ErrSSRtxBadOuts, err) } - if stake.IsSSRtx(ssrtxTxBadVerOut.MsgTx()) { + if IsSSRtx(ssrtxTxBadVerOut.MsgTx()) { t.Errorf("IsSSRtx claimed an invalid ssrtx is valid") } @@ -747,12 +746,12 @@ func TestIsSSRtxErrors(t *testing.T) { ssrtxTestRevocOutputUntagged.SetTree(wire.TxTreeStake) ssrtxTestRevocOutputUntagged.SetIndex(0) - err = stake.CheckSSRtx(ssrtxTestRevocOutputUntagged.MsgTx()) - if !errors.As(err, &serr) || serr.GetCode() != stake.ErrSSRtxBadOuts { + err = CheckSSRtx(ssrtxTestRevocOutputUntagged.MsgTx()) + if !errors.As(err, &serr) || !errors.Is(serr, ErrSSRtxBadOuts) { t.Errorf("CheckSSRtx should have returned %v but instead returned %v", - stake.ErrSSRtxBadOuts, err) + ErrSSRtxBadOuts, err) } - if stake.IsSSRtx(ssrtxTestRevocOutputUntagged.MsgTx()) { + if IsSSRtx(ssrtxTestRevocOutputUntagged.MsgTx()) { t.Errorf("IsSSRtx claimed an invalid ssrtx is valid") } @@ -778,12 +777,12 @@ func TestIsSSRtxErrors(t *testing.T) { ssrtxWrongTreeIns.SetTree(wire.TxTreeStake) ssrtxWrongTreeIns.SetIndex(0) - err = stake.CheckSSRtx(ssrtxWrongTreeIns.MsgTx()) - if !errors.As(err, &serr) || serr.GetCode() != stake.ErrSSRtxWrongTxTree { + err = CheckSSRtx(ssrtxWrongTreeIns.MsgTx()) + if !errors.As(err, &serr) || !errors.Is(serr, ErrSSRtxWrongTxTree) { t.Errorf("CheckSSRtx should have returned %v but instead returned %v", - stake.ErrSSGenWrongTxTree, err) + ErrSSGenWrongTxTree, err) } - if stake.IsSSRtx(ssrtxWrongTreeIns.MsgTx()) { + if IsSSRtx(ssrtxWrongTreeIns.MsgTx()) { t.Errorf("IsSSRtx claimed an invalid ssrtx is valid") } } @@ -795,7 +794,7 @@ func TestGetSSGenBlockVotedOn(t *testing.T) { ssgen.SetTree(wire.TxTreeStake) ssgen.SetIndex(0) - blockHash, height := stake.SSGenBlockVotedOn(ssgen.MsgTx()) + blockHash, height := SSGenBlockVotedOn(ssgen.MsgTx()) correctBlockHash, _ := chainhash.NewHash( []byte{ @@ -845,7 +844,7 @@ func TestGetSStxStakeOutputInfo(t *testing.T) { correctLimit := uint16(4) typs, pkhs, amts, changeAmts, rules, limits := - stake.TxSStxStakeOutputInfo(sstx.MsgTx()) + TxSStxStakeOutputInfo(sstx.MsgTx()) if typs[2] != correctTyp { t.Errorf("Error thrown on TestGetSStxStakeOutputInfo: Looking for "+ @@ -885,7 +884,7 @@ func TestGetSSGenVoteBits(t *testing.T) { correctvbs := uint16(0x8c94) - votebits := stake.SSGenVoteBits(ssgen.MsgTx()) + votebits := SSGenVoteBits(ssgen.MsgTx()) if correctvbs != votebits { t.Errorf("Error thrown on TestGetSSGenVoteBits: Looking for "+ @@ -896,8 +895,8 @@ func TestGetSSGenVoteBits(t *testing.T) { func TestGetSSGenVersion(t *testing.T) { var ssgen = ssgenMsgTx.Copy() - missingVersion := uint32(stake.VoteConsensusVersionAbsent) - version := stake.SSGenVersion(ssgen) + missingVersion := uint32(VoteConsensusVersionAbsent) + version := SSGenVersion(ssgen) if version != missingVersion { t.Errorf("Error thrown on TestGetSSGenVersion: Looking for "+ "version % x, got version % x", missingVersion, version) @@ -910,7 +909,7 @@ func TestGetSSGenVersion(t *testing.T) { t.Errorf("GenerateProvablyPruneableOut error %v", err) } ssgen.TxOut[1].PkScript = pkScript - version = stake.SSGenVersion(ssgen) + version = SSGenVersion(ssgen) if version != expectedVersion { t.Errorf("Error thrown on TestGetSSGenVersion: Looking for "+ @@ -931,7 +930,7 @@ func TestGetSStxNullOutputAmounts(t *testing.T) { } amtTicket := int64(0x9122e300) - _, _, err := stake.SStxNullOutputAmounts( + _, _, err := SStxNullOutputAmounts( []int64{ 0x12000000, 0x12300000, @@ -947,7 +946,7 @@ func TestGetSStxNullOutputAmounts(t *testing.T) { } // too small amount to commit - _, _, err = stake.SStxNullOutputAmounts( + _, _, err = SStxNullOutputAmounts( commitAmts, changeAmts, int64(0x00000000)) @@ -963,16 +962,16 @@ func TestGetSStxNullOutputAmounts(t *testing.T) { 0x12300001, } - var serr stake.RuleError - _, _, err = stake.SStxNullOutputAmounts( + var serr RuleError + _, _, err = SStxNullOutputAmounts( commitAmts, tooMuchChangeAmts, int64(0x00000020)) - if !errors.As(err, &serr) || serr.GetCode() != stake.ErrSStxBadChangeAmts { + if !errors.As(err, &serr) || !errors.Is(serr, ErrSStxBadChangeAmts) { t.Errorf("TestGetSStxNullOutputAmounts unexpected error: %v", err) } - fees, amts, err := stake.SStxNullOutputAmounts(commitAmts, + fees, amts, err := SStxNullOutputAmounts(commitAmts, changeAmts, amtTicket) @@ -1009,7 +1008,7 @@ func TestGetStakeRewards(t *testing.T) { amountTicket := int64(42000000) subsidy := int64(400000) - outAmts := stake.CalculateRewards(amounts, amountTicket, subsidy) + outAmts := CalculateRewards(amounts, amountTicket, subsidy) // SSRtx example with 0 subsidy expectedAmts := []int64{ @@ -1083,7 +1082,7 @@ func TestIsNullDataScript(t *testing.T) { test.name, err) } - result := stake.IsNullDataScript(test.version, script) + result := IsNullDataScript(test.version, script) if result != test.expected { t.Fatalf("%s: expected %v, got %v", test.name, test.expected, result) diff --git a/blockchain/stake/tickets.go b/blockchain/stake/tickets.go index adab2a77c9..54eb87a6e6 100644 --- a/blockchain/stake/tickets.go +++ b/blockchain/stake/tickets.go @@ -321,7 +321,8 @@ func LoadBestNode(dbTx database.Tx, height uint32, blockHash chainhash.Hash, hea return nil, err } if state.Hash != blockHash || state.Height != height { - return nil, stakeRuleError(ErrDatabaseCorrupt, "best state corruption") + str := "best state corruption" + return nil, stakeRuleError(ErrDatabaseCorrupt, str) } // Restore the best node treaps form the database. @@ -334,10 +335,9 @@ func LoadBestNode(dbTx database.Tx, height uint32, blockHash chainhash.Hash, hea return nil, err } if node.liveTickets.Len() != int(state.Live) { - return nil, stakeRuleError(ErrDatabaseCorrupt, - fmt.Sprintf("live tickets corruption (got "+ - "%v in state but loaded %v)", int(state.Live), - node.liveTickets.Len())) + str := fmt.Sprintf("live tickets corruption (got %v in state but "+ + "loaded %v)", int(state.Live), node.liveTickets.Len()) + return nil, stakeRuleError(ErrDatabaseCorrupt, str) } node.missedTickets, err = ticketdb.DbLoadAllTickets(dbTx, dbnamespace.MissedTicketsBucketName) @@ -345,10 +345,9 @@ func LoadBestNode(dbTx database.Tx, height uint32, blockHash chainhash.Hash, hea return nil, err } if node.missedTickets.Len() != int(state.Missed) { - return nil, stakeRuleError(ErrDatabaseCorrupt, - fmt.Sprintf("missed tickets corruption (got "+ - "%v in state but loaded %v)", int(state.Missed), - node.missedTickets.Len())) + str := fmt.Sprintf("missed tickets corruption (got %v in state but "+ + "loaded %v)", int(state.Missed), node.missedTickets.Len()) + return nil, stakeRuleError(ErrDatabaseCorrupt, str) } node.revokedTickets, err = ticketdb.DbLoadAllTickets(dbTx, dbnamespace.RevokedTicketsBucketName) @@ -356,10 +355,9 @@ func LoadBestNode(dbTx database.Tx, height uint32, blockHash chainhash.Hash, hea return nil, err } if node.revokedTickets.Len() != int(state.Revoked) { - return nil, stakeRuleError(ErrDatabaseCorrupt, - fmt.Sprintf("revoked tickets corruption (got "+ - "%v in state but loaded %v)", int(state.Revoked), - node.revokedTickets.Len())) + str := fmt.Sprintf("revoked tickets corruption (got %v in state but "+ + "loaded %v)", int(state.Revoked), node.revokedTickets.Len()) + return nil, stakeRuleError(ErrDatabaseCorrupt, str) } // Restore the node undo and new tickets data. @@ -425,10 +423,9 @@ func hashInSlice(h chainhash.Hash, list []chainhash.Hash) bool { func safeGet(t *tickettreap.Immutable, k tickettreap.Key) (*tickettreap.Value, error) { v := t.Get(k) if v == nil { - h := chainhash.Hash(k) - return nil, stakeRuleError(ErrMissingTicket, fmt.Sprintf( - "ticket %v was supposed to be in the passed "+ - "treap, but could not be found", h)) + str := fmt.Sprintf("ticket %v was supposed to be in the passed "+ + "treap, but could not be found", chainhash.Hash(k)) + return nil, stakeRuleError(ErrMissingTicket, str) } return &tickettreap.Value{ @@ -447,8 +444,9 @@ func safeGet(t *tickettreap.Immutable, k tickettreap.Key) (*tickettreap.Value, e // treap value are valid. func safePut(t *tickettreap.Immutable, k tickettreap.Key, v *tickettreap.Value) (*tickettreap.Immutable, error) { if t.Has(k) { - return nil, stakeRuleError(ErrDuplicateTicket, fmt.Sprintf("attempted "+ - "to insert duplicate key %v into treap", chainhash.Hash(k))) + str := fmt.Sprintf("attempted to insert duplicate key %v into treap", + chainhash.Hash(k)) + return nil, stakeRuleError(ErrDuplicateTicket, str) } return t.Put(k, v), nil @@ -459,8 +457,9 @@ func safePut(t *tickettreap.Immutable, k tickettreap.Key, v *tickettreap.Value) // the key exists in the treap. If it does not, it returns an error. func safeDelete(t *tickettreap.Immutable, k tickettreap.Key) (*tickettreap.Immutable, error) { if !t.Has(k) { - return nil, stakeRuleError(ErrMissingTicket, fmt.Sprintf("attempted to "+ - "delete non-existing key %v from treap", chainhash.Hash(k))) + str := fmt.Sprintf("attempted to delete non-existing key %v "+ + "from treap", chainhash.Hash(k)) + return nil, stakeRuleError(ErrMissingTicket, str) } return t.Delete(k), nil @@ -494,9 +493,9 @@ func connectNode(node *Node, lotteryIV chainhash.Hash, ticketsVoted, revokedTick // Basic sanity check. for i := range ticketsVoted { if !hashInSlice(ticketsVoted[i], node.nextWinners) { - return nil, stakeRuleError(ErrUnknownTicketSpent, - fmt.Sprintf("unknown ticket %v spent in block", - ticketsVoted[i])) + str := fmt.Sprintf("unknown ticket %v spent in block", + ticketsVoted[i]) + return nil, stakeRuleError(ErrUnknownTicketSpent, str) } } @@ -717,8 +716,9 @@ func disconnectNode(node *Node, parentLotteryIV chainhash.Hash, parentUtds UndoT // disk. if parentUtds == nil || parentTickets == nil { if dbTx == nil { - return nil, stakeRuleError(ErrMissingDatabaseTx, "needed to "+ - "look up undo data in the database, but no dbtx passed") + str := "needed to look up undo data in the database, but " + + "no dbtx passed" + return nil, stakeRuleError(ErrMissingDatabaseTx, str) } var err error @@ -827,8 +827,8 @@ func disconnectNode(node *Node, parentLotteryIV chainhash.Hash, parentUtds UndoT } default: - return nil, stakeRuleError(ErrMemoryCorruption, - "unknown ticket state in undo data") + str := "unknown ticket state in undo data" + return nil, stakeRuleError(ErrMemoryCorruption, str) } } @@ -916,8 +916,8 @@ func WriteConnectedBestNode(dbTx database.Tx, node *Node, hash chainhash.Hash) e } default: - return stakeRuleError(ErrMemoryCorruption, - "unknown ticket state in undo data") + str := "unknown ticket state in undo data" + return stakeRuleError(ErrMemoryCorruption, str) } } @@ -1047,8 +1047,8 @@ func WriteDisconnectedBestNode(dbTx database.Tx, node *Node, hash chainhash.Hash } default: - return stakeRuleError(ErrMemoryCorruption, - "unknown ticket state in undo data") + str := "unknown ticket state in undo data" + return stakeRuleError(ErrMemoryCorruption, str) } } diff --git a/blockchain/stake/tickets_test.go b/blockchain/stake/tickets_test.go index ea081b1e54..e535907965 100644 --- a/blockchain/stake/tickets_test.go +++ b/blockchain/stake/tickets_test.go @@ -887,9 +887,9 @@ func TestTicketDBGeneral(t *testing.T) { var rerr RuleError _, err = n161Copy.ConnectNode(b162LotteryIV, n162Test.SpentByBlock(), revokedTicketsInBlock(b162), n162Test.NewTickets()) - if !errors.As(err, &rerr) || rerr.GetCode() != ErrMissingTicket { - t.Errorf("unexpected wrong or no error for "+ - "Best node missing ticket in live ticket bucket to spend: %v", err) + if !errors.As(err, &rerr) || !errors.Is(rerr, ErrMissingTicket) { + t.Errorf("unexpected wrong or no error for best node missing ticket "+ + "in live ticket bucket to spend: %v", err) } // Duplicate best winners. @@ -900,9 +900,9 @@ func TestTicketDBGeneral(t *testing.T) { spentInBlock[0] = spentInBlock[1] _, err = n161Copy.ConnectNode(b162LotteryIV, spentInBlock, revokedTicketsInBlock(b162), n162Test.NewTickets()) - if !errors.As(err, &rerr) || rerr.GetCode() != ErrMissingTicket { - t.Errorf("unexpected wrong or no error for "+ - "Best node missing ticket in live ticket bucket to spend: %v", err) + if !errors.As(err, &rerr) || !errors.Is(rerr, ErrMissingTicket) { + t.Errorf("unexpected wrong or no error for best node missing ticket "+ + "in live ticket bucket to spend: %v", err) } // Test for corrupted spentInBlock. @@ -911,7 +911,7 @@ func TestTicketDBGeneral(t *testing.T) { spentInBlock[4] = someHash _, err = nodesForward[161].ConnectNode(b162LotteryIV, spentInBlock, revokedTicketsInBlock(b162), n162Test.NewTickets()) - if !errors.As(err, &rerr) || rerr.GetCode() != ErrUnknownTicketSpent { + if !errors.As(err, &rerr) || !errors.Is(rerr, ErrUnknownTicketSpent) { t.Errorf("unexpected wrong or no error for "+ "Test for corrupted spentInBlock: %v", err) } @@ -921,9 +921,8 @@ func TestTicketDBGeneral(t *testing.T) { n161Copy.nextWinners[4] = someHash _, err = n161Copy.ConnectNode(b162LotteryIV, spentInBlock, revokedTicketsInBlock(b162), n162Test.NewTickets()) - if !errors.As(err, &rerr) || rerr.GetCode() != ErrMissingTicket { - t.Errorf("unexpected wrong or no error for "+ - "Corrupt winners: %v", err) + if !errors.As(err, &rerr) || !errors.Is(rerr, ErrMissingTicket) { + t.Errorf("unexpected wrong or no error for corrupt winners: %v", err) } // Unknown missed ticket. @@ -931,9 +930,9 @@ func TestTicketDBGeneral(t *testing.T) { spentInBlock = n162Copy.SpentByBlock() _, err = nodesForward[161].ConnectNode(b162LotteryIV, spentInBlock, append(revokedTicketsInBlock(b162), someHash), n162Copy.NewTickets()) - if !errors.As(err, &rerr) || rerr.GetCode() != ErrMissingTicket { - t.Errorf("unexpected wrong or no error for "+ - "Unknown missed ticket: %v", err) + if !errors.As(err, &rerr) || !errors.Is(rerr, ErrMissingTicket) { + t.Errorf("unexpected wrong or no error for unknown missed "+ + "ticket: %v", err) } // Insert a duplicate new ticket. @@ -941,9 +940,9 @@ func TestTicketDBGeneral(t *testing.T) { newTicketsDup := []chainhash.Hash{someHash, someHash} _, err = nodesForward[161].ConnectNode(b162LotteryIV, spentInBlock, revokedTicketsInBlock(b162), newTicketsDup) - if !errors.As(err, &rerr) || rerr.GetCode() != ErrDuplicateTicket { - t.Errorf("unexpected wrong or no error for "+ - "Insert a duplicate new ticket: %v", err) + if !errors.As(err, &rerr) || !errors.Is(rerr, ErrDuplicateTicket) { + t.Errorf("unexpected wrong or no error for insert a duplicate "+ + "new ticket: %v", err) } // Impossible undo data for disconnecting. @@ -982,9 +981,9 @@ func TestTicketDBGeneral(t *testing.T) { n162Copy.databaseUndoUpdate[0].Revoked = false _, err = n162Copy.DisconnectNode(b161LotteryIV, n161Copy.UndoData(), n161Copy.NewTickets(), nil) - if !errors.As(err, &rerr) || rerr.GetCode() != ErrMissingTicket { - t.Errorf("unexpected wrong or no error for "+ - "Unknown undo data for disconnecting (missing): %v", err) + if !errors.As(err, &rerr) || !errors.Is(rerr, ErrMissingTicket) { + t.Errorf("unexpected wrong or no error for unknown undo data for "+ + "disconnecting (missing): %v", err) } // Unknown undo data hash when disconnecting (revoked). @@ -997,8 +996,8 @@ func TestTicketDBGeneral(t *testing.T) { n162Copy.databaseUndoUpdate[0].Revoked = true _, err = n162Copy.DisconnectNode(b161LotteryIV, n161Copy.UndoData(), n161Copy.NewTickets(), nil) - if !errors.As(err, &rerr) || rerr.GetCode() != ErrMissingTicket { - t.Errorf("unexpected wrong or no error for "+ - "Unknown undo data for disconnecting (revoked): %v", err) + if !errors.As(err, &rerr) || !errors.Is(rerr, ErrMissingTicket) { + t.Errorf("unexpected wrong or no error for unknown undo data for "+ + "disconnecting (revoked): %v", err) } }