-
Notifications
You must be signed in to change notification settings - Fork 0
/
configset.go
171 lines (151 loc) · 4.8 KB
/
configset.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
166
167
168
169
170
171
package params
import (
"github.com/pkg/errors"
fieldparams "github.com/prysmaticlabs/prysm/v4/config/fieldparams"
)
var configs *configset
// All returns a slice of every BeaconChainConfig contained in the configset.
func All() []*BeaconChainConfig {
return configs.all()
}
// ByName returns the BeaconChainConfig with the matching `ConfigName` field.
// The runtime ensures that each config name uniquely refers to a single BeaconChainConfig.
func ByName(name string) (*BeaconChainConfig, error) {
return configs.byName(name)
}
// ByVersion returns the BeaconChainConfig that has the given version in its ForkVersionSchedule.
// The configset ensures that each fork version schedule entry uniquely points to a single BeaconChainConfig.
func ByVersion(version [fieldparams.VersionLength]byte) (*BeaconChainConfig, error) {
return configs.byVersion(version)
}
// SetActive sets the given config as active (the config that will be returned by GetActive).
// SetActive will always overwrite any config with the same ConfigName before setting the updated value to active.
func SetActive(c *BeaconChainConfig) error {
return configs.setActive(c)
}
// SetActiveWithUndo attempts to set the active config, and if successful,
// returns a callback function that can be used to revert the configset back to its previous state.
func SetActiveWithUndo(c *BeaconChainConfig) (func() error, error) {
return configs.setActiveWithUndo(c)
}
type configset struct {
active *BeaconChainConfig
versionToName map[[fieldparams.VersionLength]byte]string
nameToConfig map[string]*BeaconChainConfig
}
func newConfigset(configs ...*BeaconChainConfig) *configset {
r := &configset{
versionToName: make(map[[fieldparams.VersionLength]byte]string),
nameToConfig: make(map[string]*BeaconChainConfig),
}
for _, c := range configs {
if err := r.add(c); err != nil {
panic(err)
}
}
return r
}
var errCannotNullifyActive = errors.New("cannot set a config marked as active to nil")
var errCollisionFork = errors.New("configset cannot add config with conflicting fork version schedule")
var errCollisionName = errors.New("config with conflicting name already exists")
var errConfigNotFound = errors.New("unable to find requested BeaconChainConfig")
var errReplaceNilConfig = errors.New("replace called with a nil value")
func (r *configset) add(c *BeaconChainConfig) error {
name := c.ConfigName
if _, exists := r.nameToConfig[name]; exists {
return errors.Wrapf(errCollisionName, "ConfigName=%s", name)
}
c.InitializeForkSchedule()
for v := range c.ForkVersionSchedule {
if n, exists := r.versionToName[v]; exists {
return errors.Wrapf(errCollisionFork, "config name=%s conflicts with existing config named=%s", name, n)
}
r.versionToName[v] = name
}
r.nameToConfig[name] = c
return nil
}
func (r *configset) delete(name string) {
c, exists := r.nameToConfig[name]
if !exists {
return
}
for v := range c.ForkVersionSchedule {
delete(r.versionToName, v)
}
delete(r.nameToConfig, name)
}
func (r *configset) replace(cfg *BeaconChainConfig) error {
if cfg == nil {
return errReplaceNilConfig
}
name := cfg.ConfigName
r.delete(name)
if err := r.add(cfg); err != nil {
return err
}
if r.active != nil && r.active.ConfigName == name {
r.active = cfg
}
return nil
}
func (r *configset) replaceWithUndo(cfg *BeaconChainConfig) (func() error, error) {
name := cfg.ConfigName
prev := r.nameToConfig[name]
if err := r.replace(cfg); err != nil {
return nil, err
}
return func() error {
if prev == nil {
if r.active.ConfigName == name {
return errors.Wrapf(errCannotNullifyActive, "active config name=%s", name)
}
r.delete(name)
return nil
}
return r.replace(prev)
}, nil
}
func (r *configset) getActive() *BeaconChainConfig {
return r.active
}
func (r *configset) setActive(c *BeaconChainConfig) error {
if err := r.replace(c); err != nil {
return err
}
r.active = c
return nil
}
func (r *configset) setActiveWithUndo(c *BeaconChainConfig) (func() error, error) {
active := r.active
r.active = c
undo, err := r.replaceWithUndo(c)
if err != nil {
return nil, err
}
return func() error {
r.active = active
return undo()
}, nil
}
func (r *configset) byName(name string) (*BeaconChainConfig, error) {
c, ok := r.nameToConfig[name]
if !ok {
return nil, errors.Wrapf(errConfigNotFound, "name=%s is not a known BeaconChainConfig name", name)
}
return c, nil
}
func (r *configset) byVersion(version [fieldparams.VersionLength]byte) (*BeaconChainConfig, error) {
name, ok := r.versionToName[version]
if !ok {
return nil, errors.Wrapf(errConfigNotFound, "version=%#x not found in any known fork choice schedule", version)
}
return r.byName(name)
}
func (r *configset) all() []*BeaconChainConfig {
all := make([]*BeaconChainConfig, 0)
for _, c := range r.nameToConfig {
all = append(all, c)
}
return all
}