-
Notifications
You must be signed in to change notification settings - Fork 646
/
validator_uptimes.go
165 lines (144 loc) · 4.46 KB
/
validator_uptimes.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
161
162
163
164
165
// Copyright (C) 2019-2021, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package state
import (
"time"
"github.com/ava-labs/avalanchego/database"
"github.com/ava-labs/avalanchego/ids"
"github.com/ava-labs/avalanchego/utils/constants"
"github.com/ava-labs/avalanchego/utils/set"
"github.com/ava-labs/avalanchego/vms/platformvm/genesis"
"github.com/ava-labs/avalanchego/vms/platformvm/txs"
)
var _ validatorUptimes = (*uptimes)(nil)
type uptimeAndReward struct {
UpDuration time.Duration `serialize:"true"`
LastUpdated uint64 `serialize:"true"` // Unix time in seconds
PotentialReward uint64 `serialize:"true"`
txID ids.ID
lastUpdated time.Time
}
type validatorUptimes interface {
// LoadUptime sets the uptime measurements of [vdrID] on [subnetID] to
// [uptime]. GetUptime and SetUptime will return an error if the [vdrID] and
// [subnetID] hasn't been loaded. This call will not result in a write to disk.
LoadUptime(
vdrID ids.NodeID,
subnetID ids.ID,
uptime *uptimeAndReward,
)
// GetUptime returns the current uptime measurements of [vdrID] on
// [subnetID].
GetUptime(
vdrID ids.NodeID,
subnetID ids.ID,
) (upDuration time.Duration, lastUpdated time.Time, err error)
// SetUptime updates the uptime measurements of [vdrID] on [subnetID].
// Unless these measurements are deleted first, the next call to
// WriteUptimes will write this update to disk.
SetUptime(
vdrID ids.NodeID,
subnetID ids.ID,
upDuration time.Duration,
lastUpdated time.Time,
) error
// DeleteUptime removes in-memory references to the uptimes measurements of
// [vdrID] on [subnetID]. If there were staged updates from a prior call to
// SetUptime, the updates will be dropped. This call will not result in a
// write to disk.
DeleteUptime(vdrID ids.NodeID, subnetID ids.ID)
// WriteUptimes writes all staged updates from a prior call to SetUptime.
WriteUptimes(
dbPrimary database.KeyValueWriter,
dbSubnet database.KeyValueWriter,
) error
}
type uptimes struct {
uptimes map[ids.NodeID]map[ids.ID]*uptimeAndReward // vdrID -> subnetID -> uptimes
// updatedUptimes tracks the updates since the last call to WriteUptimes
updatedUptimes map[ids.NodeID]set.Set[ids.ID] // vdrID -> subnetIDs
}
func newValidatorUptimes() validatorUptimes {
return &uptimes{
uptimes: make(map[ids.NodeID]map[ids.ID]*uptimeAndReward),
updatedUptimes: make(map[ids.NodeID]set.Set[ids.ID]),
}
}
func (u *uptimes) LoadUptime(
vdrID ids.NodeID,
subnetID ids.ID,
uptime *uptimeAndReward,
) {
subnetUptimes, ok := u.uptimes[vdrID]
if !ok {
subnetUptimes = make(map[ids.ID]*uptimeAndReward)
u.uptimes[vdrID] = subnetUptimes
}
subnetUptimes[subnetID] = uptime
}
func (u *uptimes) GetUptime(
vdrID ids.NodeID,
subnetID ids.ID,
) (upDuration time.Duration, lastUpdated time.Time, err error) {
uptime, exists := u.uptimes[vdrID][subnetID]
if !exists {
return 0, time.Time{}, database.ErrNotFound
}
return uptime.UpDuration, uptime.lastUpdated, nil
}
func (u *uptimes) SetUptime(
vdrID ids.NodeID,
subnetID ids.ID,
upDuration time.Duration,
lastUpdated time.Time,
) error {
uptime, exists := u.uptimes[vdrID][subnetID]
if !exists {
return database.ErrNotFound
}
uptime.UpDuration = upDuration
uptime.lastUpdated = lastUpdated
updatedSubnetUptimes, ok := u.updatedUptimes[vdrID]
if !ok {
updatedSubnetUptimes = set.Set[ids.ID]{}
u.updatedUptimes[vdrID] = updatedSubnetUptimes
}
updatedSubnetUptimes.Add(subnetID)
return nil
}
func (u *uptimes) DeleteUptime(vdrID ids.NodeID, subnetID ids.ID) {
subnetUptimes := u.uptimes[vdrID]
delete(subnetUptimes, subnetID)
if len(subnetUptimes) == 0 {
delete(u.uptimes, vdrID)
}
subnetUpdatedUptimes := u.updatedUptimes[vdrID]
delete(subnetUpdatedUptimes, subnetID)
if len(subnetUpdatedUptimes) == 0 {
delete(u.updatedUptimes, vdrID)
}
}
func (u *uptimes) WriteUptimes(
dbPrimary database.KeyValueWriter,
dbSubnet database.KeyValueWriter,
) error {
for vdrID, updatedSubnets := range u.updatedUptimes {
for subnetID := range updatedSubnets {
uptime := u.uptimes[vdrID][subnetID]
uptime.LastUpdated = uint64(uptime.lastUpdated.Unix())
uptimeBytes, err := genesis.Codec.Marshal(txs.Version, uptime)
if err != nil {
return err
}
db := dbSubnet
if subnetID == constants.PrimaryNetworkID {
db = dbPrimary
}
if err := db.Put(uptime.txID[:], uptimeBytes); err != nil {
return err
}
}
delete(u.updatedUptimes, vdrID)
}
return nil
}