1 // Copyright (c) 2014-2016 The btcsuite developers
2 // Use of this source code is governed by an ISC
3 // license that can be found in the LICENSE file.
8 "github.com/btcsuite/btcd/blockchain"
9 "github.com/btcsuite/btcd/wire"
12 // RuleError identifies a rule violation. It is used to indicate that
13 // processing of a transaction failed due to one of the many validation
14 // rules. The caller can use type assertions to determine if a failure was
15 // specifically due to a rule violation and use the Err field to access the
16 // underlying error, which will be either a TxRuleError or a
17 // blockchain.RuleError.
18 type RuleError struct {
22 // Error satisfies the error interface and prints human-readable errors.
23 func (e RuleError) Error() string {
30 // TxRuleError identifies a rule violation. It is used to indicate that
31 // processing of a transaction failed due to one of the many validation
32 // rules. The caller can use type assertions to determine if a failure was
33 // specifically due to a rule violation and access the ErrorCode field to
34 // ascertain the specific reason for the rule violation.
35 type TxRuleError struct {
36 RejectCode wire.RejectCode // The code to send with reject messages
37 Description string // Human readable description of the issue
40 // Error satisfies the error interface and prints human-readable errors.
41 func (e TxRuleError) Error() string {
45 // txRuleError creates an underlying TxRuleError with the given a set of
46 // arguments and returns a RuleError that encapsulates it.
47 func txRuleError(c wire.RejectCode, desc string) RuleError {
49 Err: TxRuleError{RejectCode: c, Description: desc},
53 // chainRuleError returns a RuleError that encapsulates the given
54 // blockchain.RuleError.
55 func chainRuleError(chainErr blockchain.RuleError) RuleError {
61 // extractRejectCode attempts to return a relevant reject code for a given error
62 // by examining the error for known types. It will return true if a code
63 // was successfully extracted.
64 func extractRejectCode(err error) (wire.RejectCode, bool) {
65 // Pull the underlying error out of a RuleError.
66 if rerr, ok := err.(RuleError); ok {
70 switch err := err.(type) {
71 case blockchain.RuleError:
72 // Convert the chain error to a reject code.
73 var code wire.RejectCode
74 switch err.ErrorCode {
75 // Rejected due to duplicate.
76 case blockchain.ErrDuplicateBlock:
77 code = wire.RejectDuplicate
79 // Rejected due to obsolete version.
80 case blockchain.ErrBlockVersionTooOld:
81 code = wire.RejectObsolete
83 // Rejected due to checkpoint.
84 case blockchain.ErrCheckpointTimeTooOld:
86 case blockchain.ErrDifficultyTooLow:
88 case blockchain.ErrBadCheckpoint:
90 case blockchain.ErrForkTooOld:
91 code = wire.RejectCheckpoint
93 // Everything else is due to the block or transaction being invalid.
95 code = wire.RejectInvalid
101 return err.RejectCode, true
104 return wire.RejectInvalid, false
107 return wire.RejectInvalid, false
110 // ErrToRejectErr examines the underlying type of the error and returns a reject
111 // code and string appropriate to be sent in a wire.MsgReject message.
112 func ErrToRejectErr(err error) (wire.RejectCode, string) {
113 // Return the reject code along with the error text if it can be
114 // extracted from the error.
115 rejectCode, found := extractRejectCode(err)
117 return rejectCode, err.Error()
120 // Return a generic rejected string if there is no error. This really
121 // should not happen unless the code elsewhere is not setting an error
122 // as it should be, but it's best to be safe and simply return a generic
123 // string rather than allowing the following code that dereferences the
126 return wire.RejectInvalid, "rejected"
129 // When the underlying error is not one of the above cases, just return
130 // wire.RejectInvalid with a generic rejected string plus the error
132 return wire.RejectInvalid, "rejected: " + err.Error()