You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
135 lines
4.1 KiB
135 lines
4.1 KiB
// Copyright (c) 2014 The btcsuite developers |
|
// Use of this source code is governed by an ISC |
|
// license that can be found in the LICENSE file. |
|
|
|
package main |
|
|
|
import ( |
|
"github.com/btcsuite/btcd/blockchain" |
|
"github.com/btcsuite/btcd/wire" |
|
) |
|
|
|
// RuleError identifies a rule violation. It is used to indicate that |
|
// processing of a 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 use the Err field to access the |
|
// underlying error, which will be either a TxRuleError or a |
|
// blockchain.RuleError. |
|
type RuleError struct { |
|
Err error |
|
} |
|
|
|
// Error satisfies the error interface and prints human-readable errors. |
|
func (e RuleError) Error() string { |
|
if e.Err == nil { |
|
return "<nil>" |
|
} |
|
return e.Err.Error() |
|
} |
|
|
|
// TxRuleError identifies a rule violation. It is used to indicate that |
|
// processing of a 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. |
|
type TxRuleError struct { |
|
RejectCode wire.RejectCode // The code to send with reject messages |
|
Description string // Human readable description of the issue |
|
} |
|
|
|
// Error satisfies the error interface and prints human-readable errors. |
|
func (e TxRuleError) Error() string { |
|
return e.Description |
|
} |
|
|
|
// txRuleError creates an underlying TxRuleError with the given a set of |
|
// arguments and returns a RuleError that encapsulates it. |
|
func txRuleError(c wire.RejectCode, desc string) RuleError { |
|
return RuleError{ |
|
Err: TxRuleError{RejectCode: c, Description: desc}, |
|
} |
|
} |
|
|
|
// chainRuleError returns a RuleError that encapsulates the given |
|
// blockchain.RuleError. |
|
func chainRuleError(chainErr blockchain.RuleError) RuleError { |
|
return RuleError{ |
|
Err: chainErr, |
|
} |
|
} |
|
|
|
// extractRejectCode attempts to return a relevant reject code for a given error |
|
// by examining the error for known types. It will return true if a code |
|
// was successfully extracted. |
|
func extractRejectCode(err error) (wire.RejectCode, bool) { |
|
// Pull the underlying error out of a RuleError. |
|
if rerr, ok := err.(RuleError); ok { |
|
err = rerr.Err |
|
} |
|
|
|
switch err := err.(type) { |
|
case blockchain.RuleError: |
|
// Convert the chain error to a reject code. |
|
var code wire.RejectCode |
|
switch err.ErrorCode { |
|
// Rejected due to duplicate. |
|
case blockchain.ErrDuplicateBlock: |
|
fallthrough |
|
case blockchain.ErrDoubleSpend: |
|
code = wire.RejectDuplicate |
|
|
|
// Rejected due to obsolete version. |
|
case blockchain.ErrBlockVersionTooOld: |
|
code = wire.RejectObsolete |
|
|
|
// Rejected due to checkpoint. |
|
case blockchain.ErrCheckpointTimeTooOld: |
|
fallthrough |
|
case blockchain.ErrDifficultyTooLow: |
|
fallthrough |
|
case blockchain.ErrBadCheckpoint: |
|
fallthrough |
|
case blockchain.ErrForkTooOld: |
|
code = wire.RejectCheckpoint |
|
|
|
// Everything else is due to the block or transaction being invalid. |
|
default: |
|
code = wire.RejectInvalid |
|
} |
|
|
|
return code, true |
|
|
|
case TxRuleError: |
|
return err.RejectCode, true |
|
|
|
case nil: |
|
return wire.RejectInvalid, false |
|
} |
|
|
|
return wire.RejectInvalid, false |
|
} |
|
|
|
// errToRejectErr examines the underlying type of the error and returns a reject |
|
// code and string appropriate to be sent in a wire.MsgReject message. |
|
func errToRejectErr(err error) (wire.RejectCode, string) { |
|
// Return the reject code along with the error text if it can be |
|
// extracted from the error. |
|
rejectCode, found := extractRejectCode(err) |
|
if found { |
|
return rejectCode, err.Error() |
|
} |
|
|
|
// Return a generic rejected string if there is no error. This really |
|
// should not happen unless the code elsewhere is not setting an error |
|
// as it should be, but it's best to be safe and simply return a generic |
|
// string rather than allowing the following code that derferences the |
|
// err to panic. |
|
if err == nil { |
|
return wire.RejectInvalid, "rejected" |
|
} |
|
|
|
// When the underlying error is not one of the above cases, just return |
|
// wire.RejectInvalid with a generic rejected string plus the error |
|
// text. |
|
return wire.RejectInvalid, "rejected: " + err.Error() |
|
}
|
|
|