github.com/btcsuite/btcd@v0.24.0/mempool/error.go (about)

     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.
     4  
     5  package mempool
     6  
     7  import (
     8  	"github.com/btcsuite/btcd/blockchain"
     9  	"github.com/btcsuite/btcd/wire"
    10  )
    11  
    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 {
    19  	Err error
    20  }
    21  
    22  // Error satisfies the error interface and prints human-readable errors.
    23  func (e RuleError) Error() string {
    24  	if e.Err == nil {
    25  		return "<nil>"
    26  	}
    27  	return e.Err.Error()
    28  }
    29  
    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
    38  }
    39  
    40  // Error satisfies the error interface and prints human-readable errors.
    41  func (e TxRuleError) Error() string {
    42  	return e.Description
    43  }
    44  
    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 {
    48  	return RuleError{
    49  		Err: TxRuleError{RejectCode: c, Description: desc},
    50  	}
    51  }
    52  
    53  // chainRuleError returns a RuleError that encapsulates the given
    54  // blockchain.RuleError.
    55  func chainRuleError(chainErr blockchain.RuleError) RuleError {
    56  	return RuleError{
    57  		Err: chainErr,
    58  	}
    59  }
    60  
    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 {
    67  		err = rerr.Err
    68  	}
    69  
    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
    78  
    79  		// Rejected due to obsolete version.
    80  		case blockchain.ErrBlockVersionTooOld:
    81  			code = wire.RejectObsolete
    82  
    83  		// Rejected due to checkpoint.
    84  		case blockchain.ErrCheckpointTimeTooOld:
    85  			fallthrough
    86  		case blockchain.ErrDifficultyTooLow:
    87  			fallthrough
    88  		case blockchain.ErrBadCheckpoint:
    89  			fallthrough
    90  		case blockchain.ErrForkTooOld:
    91  			code = wire.RejectCheckpoint
    92  
    93  		// Everything else is due to the block or transaction being invalid.
    94  		default:
    95  			code = wire.RejectInvalid
    96  		}
    97  
    98  		return code, true
    99  
   100  	case TxRuleError:
   101  		return err.RejectCode, true
   102  
   103  	case nil:
   104  		return wire.RejectInvalid, false
   105  	}
   106  
   107  	return wire.RejectInvalid, false
   108  }
   109  
   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)
   116  	if found {
   117  		return rejectCode, err.Error()
   118  	}
   119  
   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
   124  	// err to panic.
   125  	if err == nil {
   126  		return wire.RejectInvalid, "rejected"
   127  	}
   128  
   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
   131  	// text.
   132  	return wire.RejectInvalid, "rejected: " + err.Error()
   133  }