github.com/koko1123/flow-go-1@v0.29.6/engine/errors.go (about) 1 package engine 2 3 import ( 4 "errors" 5 "fmt" 6 7 "github.com/rs/zerolog" 8 ) 9 10 var ( 11 // IncompatibleInputTypeError indicates that the input has an incompatible type 12 IncompatibleInputTypeError = errors.New("incompatible input type") 13 ) 14 15 // InvalidInputError are errors for caused by invalid inputs. 16 // It's useful to distinguish these known errors from exceptions. 17 // By distinguishing errors from exceptions, we can log them 18 // differently. 19 // For instance, log InvalidInputError error as a warn log, and log 20 // other error as an error log. 21 type InvalidInputError struct { 22 err error 23 } 24 25 func NewInvalidInputError(msg string) error { 26 return NewInvalidInputErrorf(msg) 27 } 28 29 func NewInvalidInputErrorf(msg string, args ...interface{}) error { 30 return InvalidInputError{ 31 err: fmt.Errorf(msg, args...), 32 } 33 } 34 35 func (e InvalidInputError) Unwrap() error { 36 return e.err 37 } 38 39 func (e InvalidInputError) Error() string { 40 return e.err.Error() 41 } 42 43 // IsInvalidInputError returns whether the given error is an InvalidInputError error 44 func IsInvalidInputError(err error) bool { 45 var errInvalidInputError InvalidInputError 46 return errors.As(err, &errInvalidInputError) 47 } 48 49 // IsNetworkTransmissionError returns whether the given error is a NetworkTransmissionError error 50 func IsNetworkTransmissionError(err error) bool { 51 var errNetworkTransmissionError NetworkTransmissionError 52 return errors.As(err, &errNetworkTransmissionError) 53 } 54 55 // NetworkTransmissionError captures the general sentinel errors upon network transmission. It is used to distinguish 56 // network transmission errors from other errors. 57 type NetworkTransmissionError struct { 58 err error 59 } 60 61 func NewNetworkTransmissionErrorf(msg string, args ...interface{}) error { 62 return NetworkTransmissionError{ 63 err: fmt.Errorf(msg, args...), 64 } 65 } 66 67 func NewNetworkTransmissionError(msg string) error { 68 return NetworkTransmissionError{ 69 err: fmt.Errorf(msg), 70 } 71 } 72 73 func (e NetworkTransmissionError) Unwrap() error { 74 return e.err 75 } 76 77 func (e NetworkTransmissionError) Error() string { 78 return e.err.Error() 79 } 80 81 // OutdatedInputError are for inputs that are outdated. An outdated input doesn't mean 82 // whether the input was invalid or not, knowing that would take more computation that 83 // isn't necessary. 84 // An outdated input could also for a duplicated input: the duplication is outdated. 85 type OutdatedInputError struct { 86 err error 87 } 88 89 func NewOutdatedInputErrorf(msg string, args ...interface{}) error { 90 return OutdatedInputError{ 91 err: fmt.Errorf(msg, args...), 92 } 93 } 94 95 func (e OutdatedInputError) Unwrap() error { 96 return e.err 97 } 98 99 func (e OutdatedInputError) Error() string { 100 return e.err.Error() 101 } 102 103 func IsOutdatedInputError(err error) bool { 104 var errOutdatedInputError OutdatedInputError 105 return errors.As(err, &errOutdatedInputError) 106 } 107 108 // UnverifiableInputError are for inputs that cannot be verified at this moment. 109 // Usually it means that we don't have enough data to verify it. A good example is missing 110 // data in DB to process input. 111 type UnverifiableInputError struct { 112 err error 113 } 114 115 func NewUnverifiableInputError(msg string, args ...interface{}) error { 116 return UnverifiableInputError{ 117 err: fmt.Errorf(msg, args...), 118 } 119 } 120 121 func (e UnverifiableInputError) Unwrap() error { 122 return e.err 123 } 124 125 func (e UnverifiableInputError) Error() string { 126 return e.err.Error() 127 } 128 129 func IsUnverifiableInputError(err error) bool { 130 var errUnverifiableInputError UnverifiableInputError 131 return errors.As(err, &errUnverifiableInputError) 132 } 133 134 type DuplicatedEntryError struct { 135 err error 136 } 137 138 func NewDuplicatedEntryErrorf(msg string, args ...interface{}) error { 139 return DuplicatedEntryError{ 140 err: fmt.Errorf(msg, args...), 141 } 142 } 143 144 func (e DuplicatedEntryError) Unwrap() error { 145 return e.err 146 } 147 148 func (e DuplicatedEntryError) Error() string { 149 return e.err.Error() 150 } 151 152 func IsDuplicatedEntryError(err error) bool { 153 var errDuplicatedEntryError DuplicatedEntryError 154 return errors.As(err, &errDuplicatedEntryError) 155 } 156 157 // LogError logs the engine processing error 158 func LogError(log zerolog.Logger, err error) { 159 LogErrorWithMsg(log, "could not process message", err) 160 } 161 162 func LogErrorWithMsg(log zerolog.Logger, msg string, err error) { 163 if err == nil { 164 return 165 } 166 167 // Invalid input errors could be logged as warning, because they can be 168 // part of normal operations when the network is open and anyone can send 169 // weird messages around. However, during the non-BFT phase where we 170 // control the majority of the network, we should not be seeing any of 171 // them. Logging them as error will help us to identify and address 172 // issues with our application logic before going full BFT. 173 if IsInvalidInputError(err) { 174 log.Error().Str("error_type", "invalid_input").Err(err).Msg(msg) 175 return 176 } 177 178 // Outdated input errors, on the other hand, can happen regularly, even 179 // before opening the network up, as some messages might just be late 180 // due to network delays or other infrastructure issues. They should 181 // thus be logged as warnings. 182 if IsOutdatedInputError(err) { 183 log.Warn().Str("error_type", "outdated_input").Err(err).Msg(msg) 184 return 185 } 186 187 // Unverifiable input errors may be due to out-of-date node state, or could 188 // indicate a malicious/unexpected message from another node. Since we don't 189 // know, log as warning. 190 if IsUnverifiableInputError(err) { 191 log.Warn().Str("error_type", "unverifiable_input").Err(err).Msg(msg) 192 return 193 } 194 195 // all other errors should just be logged as usual 196 log.Error().Str("error_type", "internal_error").Err(err).Msg(msg) 197 } 198 199 func IsIncompatibleInputTypeError(err error) bool { 200 return errors.Is(err, IncompatibleInputTypeError) 201 }