github.com/lbryio/lbcd@v0.22.119/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/lbryio/lbcd/blockchain" 9 "github.com/lbryio/lbcd/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 }