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