-
Notifications
You must be signed in to change notification settings - Fork 649
/
compatibility.go
140 lines (114 loc) · 3.56 KB
/
compatibility.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
// (c) 2019-2020, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package version
import (
"errors"
"time"
"github.com/ava-labs/avalanchego/utils/timer"
)
var (
errIncompatible = errors.New("peers version is incompatible")
errMaskable = errors.New("peers version is maskable")
_ Compatibility = &compatibility{}
)
// Compatibility a utility for checking the compatibility of peer versions
type Compatibility interface {
// Returns the local version
Version() Application
// Returns nil if the provided version is compatible with the local version.
// This means that the version is connectable and that consensus messages
// can be made to them.
Compatible(Application) error
// Returns nil if the provided version shouldn't be masked. This means that
// the version is connectable but not compatible. The version is so old that
// it should just be masked.
Unmaskable(Application) error
// Returns nil if the provided version will not be masked by this version.
WontMask(Application) error
// Returns when additional masking will occur.
MaskTime() time.Time
}
type compatibility struct {
version Application
minCompatable Application
minCompatableTime time.Time
prevMinCompatable Application
minUnmaskable Application
minUnmaskableTime time.Time
prevMinUnmaskable Application
clock timer.Clock
}
// NewCompatibility returns a compatibility checker with the provided options
func NewCompatibility(
version Application,
minCompatable Application,
minCompatableTime time.Time,
prevMinCompatable Application,
minUnmaskable Application,
minUnmaskableTime time.Time,
prevMinUnmaskable Application,
) Compatibility {
return &compatibility{
version: version,
minCompatable: minCompatable,
minCompatableTime: minCompatableTime,
prevMinCompatable: prevMinCompatable,
minUnmaskable: minUnmaskable,
minUnmaskableTime: minUnmaskableTime,
prevMinUnmaskable: prevMinUnmaskable,
}
}
func (c *compatibility) Version() Application { return c.version }
func (c *compatibility) Compatible(peer Application) error {
if err := c.version.Compatible(peer); err != nil {
return err
}
if !peer.Before(c.minCompatable) {
// The peer is at least the minimum compatible version.
return nil
}
// The peer is going to be marked as incompatible at [c.minCompatableTime].
now := c.clock.Time()
if !now.Before(c.minCompatableTime) {
return errIncompatible
}
// The minCompatable check isn't being enforced yet.
if !peer.Before(c.prevMinCompatable) {
// The peer is at least the previous minimum compatible version.
return nil
}
return errIncompatible
}
func (c *compatibility) Unmaskable(peer Application) error {
if err := c.Compatible(peer); err != nil {
return err
}
if !peer.Before(c.minUnmaskable) {
// The peer is at least the minimum unmaskable version.
return nil
}
// The peer is going to be marked as maskable at [c.minUnmaskableTime].
now := c.clock.Time()
if !now.Before(c.minUnmaskableTime) {
return errMaskable
}
// The minCompatable check isn't being enforced yet.
if !peer.Before(c.prevMinUnmaskable) {
// The peer is at least the previous minimum unmaskable version.
return nil
}
return errMaskable
}
func (c *compatibility) WontMask(peer Application) error {
if err := c.Compatible(peer); err != nil {
return err
}
if !peer.Before(c.minUnmaskable) {
// The peer is at least the minimum unmaskable version.
return nil
}
return errMaskable
}
func (c *compatibility) MaskTime() time.Time {
return c.minUnmaskableTime
}