prysm-pulse/config/params/configset.go

187 lines
5.3 KiB
Go
Raw Normal View History

package params
import (
"fmt"
"github.com/pkg/errors"
fieldparams "github.com/prysmaticlabs/prysm/v5/config/fieldparams"
"github.com/prysmaticlabs/prysm/v5/runtime/version"
)
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 {
// determine the fork name for the colliding version
cfv := ConfigForkVersions(c)
versionId := cfv[v]
msg := fmt.Sprintf("version %#x for fork %s in config %s conflicts with existing config named=%s",
v, version.String(versionId), name, n)
return errors.Wrap(errCollisionFork, msg)
}
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 prev != nil {
prev = prev.Copy()
}
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) {
if r.active == nil {
return nil, errors.Wrap(errCannotNullifyActive,
"active config is currently nil, refusing to construct undo method that will leave it nil again")
}
active := r.active.Copy()
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
}