From b25e44a8414bc8aa4a8841fbc363b39a8b33dd5e Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Fri, 18 Jul 2025 13:00:36 +0200 Subject: [PATCH] params: new param system --- params/chainparam.go | 120 ++++++++++--------------------------------- params/config2.go | 41 ++++++--------- params/registry.go | 110 ++++++++++++++++++++------------------- 3 files changed, 103 insertions(+), 168 deletions(-) diff --git a/params/chainparam.go b/params/chainparam.go index d85ea4f812..36a2a89712 100644 --- a/params/chainparam.go +++ b/params/chainparam.go @@ -9,79 +9,40 @@ import ( ) // ChainID -type ChainID big.Int - -func NewChainID(input string) *ChainID { - b, ok := new(big.Int).SetString(input, 0) - if !ok { - panic("invalid chainID: " + input) - } - return (*ChainID)(b) -} - -func (v *ChainID) MarshalText() ([]byte, error) { - return (*big.Int)(v).MarshalText() -} - -func (v *ChainID) UnmarshalText(input []byte) error { - return (*big.Int)(v).UnmarshalText(input) -} - -func (v *ChainID) BigInt() *big.Int { - return (*big.Int)(v) -} - -func (v *ChainID) Validate(cfg *Config2) error { - b := (*big.Int)(v) - if b.Sign() <= 0 { - return fmt.Errorf("invalid chainID value %v", b) - } - return nil -} +var ChainID = Define(T[*big.Int]{ + Name: "chainId", + Validate: func(v *big.Int, cfg *Config2) error { + if v.Sign() <= 0 { + return fmt.Errorf("invalid chainID value %v", v) + } + return nil + }, +}) // TerminalTotalDifficulty (TTD) is the total difficulty value where -type TerminalTotalDifficulty big.Int - -func NewTerminalTotalDifficulty(input string) *TerminalTotalDifficulty { - b, ok := new(big.Int).SetString(input, 0) - if !ok { - panic("invalid terminal total difficulty: " + input) - } - return (*TerminalTotalDifficulty)(b) -} - -func (v *TerminalTotalDifficulty) MarshalText() ([]byte, error) { - return (*big.Int)(v).MarshalText() -} - -func (v *TerminalTotalDifficulty) UnmarshalText(input []byte) error { - return (*big.Int)(v).UnmarshalText(input) -} - -func (v *TerminalTotalDifficulty) BigInt() *big.Int { - return (*big.Int)(v) -} - -func (v *TerminalTotalDifficulty) Validate(cfg *Config2) error { - return nil -} +var TerminalTotalDifficulty = Define(T[*big.Int]{ + Name: "terminalTotalDifficulty", + Optional: true, +}) // DepositContractAddress configures the location of the deposit contract. -type DepositContractAddress common.Address - -func (v DepositContractAddress) Validate(cfg *Config2) error { - return nil -} +var DepositContractAddress = Define(T[common.Address]{ + Name: "depositContractAddress", + Optional: true, +}) // This configures the EIP-4844 parameters across forks. // There must be an entry for each fork -type BlobSchedule map[forks.Fork]BlobConfig +var BlobSchedule = Define(T[map[forks.Fork]BlobConfig]{ + Name: "blobSchedule", + Optional: true, + Validate: validateBlobSchedule, +}) -// Validate checks that all forks with blobs explicitly define the blob schedule configuration. -func (v BlobSchedule) Validate(cfg *Config2) error { +func validateBlobSchedule(schedule map[forks.Fork]BlobConfig, cfg *Config2) error { + // Check that all forks with blobs explicitly define the blob schedule configuration. for _, f := range forks.CanonOrder { if f.HasBlobs() { - schedule := Get[BlobSchedule](cfg) bcfg, defined := schedule[f] if cfg.Scheduled(f) && !defined { return fmt.Errorf("invalid chain configuration: missing entry for fork %q in blobSchedule", f) @@ -99,32 +60,7 @@ func (v BlobSchedule) Validate(cfg *Config2) error { // DAOForkSupport is the chain parameter that configures the DAO fork. // true=supports or false=opposes the fork. // The default value is true. -type DAOForkSupport bool - -func (v DAOForkSupport) Validate(cfg *Config2) error { - return nil -} - -func init() { - Define(Parameter[*ChainID]{ - Name: "chainId", - Optional: false, - }) - Define(Parameter[*TerminalTotalDifficulty]{ - Name: "terminalTotalDifficulty", - Optional: false, - }) - Define(Parameter[DAOForkSupport]{ - Name: "daoForkSupport", - Optional: true, - Default: true, - }) - Define(Parameter[BlobSchedule]{ - Name: "blobSchedule", - Optional: true, - }) - Define(Parameter[DepositContractAddress]{ - Name: "depositContractAddress", - Optional: true, - }) -} +var DAOForkSupport = Define(T[bool]{ + Optional: true, + Default: true, +}) diff --git a/params/config2.go b/params/config2.go index 79c7406081..8dfcbba3c4 100644 --- a/params/config2.go +++ b/params/config2.go @@ -22,7 +22,6 @@ import ( "fmt" "maps" "math/big" - "reflect" "slices" "strings" @@ -35,21 +34,17 @@ type Activations map[forks.Fork]uint64 // Config2 represents the chain configuration. type Config2 struct { activation Activations - param map[reflect.Type]ParameterType + param map[int]any } -func NewConfig2(activations Activations, param ...ParameterType) *Config2 { +func NewConfig2(activations Activations, param ...ParamValue) *Config2 { cfg := &Config2{ activation: maps.Clone(activations), - param: make(map[reflect.Type]ParameterType, len(param)), + param: make(map[int]any, len(param)), } cfg.activation[forks.Frontier] = 0 for _, pv := range param { - info, ok := findParam(pv) - if !ok { - panic(fmt.Sprintf("undefined chain parameter type %T", pv)) - } - cfg.param[info.rtype] = pv + cfg.param[pv.id] = pv.value } return cfg } @@ -109,12 +104,12 @@ func (cfg *Config2) LatestFork(time uint64) forks.Fork { func (cfg *Config2) MarshalJSON() ([]byte, error) { m := make(map[string]any) // params - for _, p := range cfg.param { - info, ok := findParam(p) + for id, value := range cfg.param { + info, ok := paramRegistry[id] if !ok { - panic(fmt.Sprintf("unknown chain parameter %T", p)) + panic(fmt.Sprintf("unknown chain parameter id %v", id)) } - m[info.name] = p + m[info.name] = value } // forks for f, act := range cfg.activation { @@ -187,15 +182,15 @@ func (cfg *Config2) decodeActivation(key string, dec *json.Decoder) error { } func (cfg *Config2) decodeParameter(key string, dec *json.Decoder) error { - info, ok := paramRegistryByName[key] + id, ok := paramRegistryByName[key] if !ok { return fmt.Errorf("unknown chain parameter %q", key) } - v := reflect.New(info.rtype).Interface() + v := paramRegistry[id].new() if err := dec.Decode(v); err != nil { return err } - cfg.param[info.rtype] = v.(ParameterType) + cfg.param[id] = v return nil } @@ -235,15 +230,15 @@ func (cfg *Config2) Validate() error { } // Check parameters. - for rtype, info := range paramRegistry { - v, isSet := cfg.param[rtype] + for id, info := range paramRegistry { + v, isSet := cfg.param[id] if !isSet { if !info.optional { return fmt.Errorf("required chain parameter %s is not set", info.name) } - v = info.defaultVal + v = info.defaultValue } - if err := v.Validate(cfg); err != nil { + if err := info.validate(v, cfg); err != nil { return fmt.Errorf("invalid %s: %w", info.name, err) } } @@ -296,12 +291,10 @@ func (cfg *Config2) checkCompatible(newcfg *Config2, num uint64, time uint64) *C } } - if cfg.Active(forks.DAO, num, time) && Get[DAOForkSupport](cfg) != Get[DAOForkSupport](newcfg) { + if cfg.Active(forks.DAO, num, time) && DAOForkSupport.Get(cfg) != DAOForkSupport.Get(newcfg) { return newBlockCompatError2("DAO fork support flag", forks.DAO, cfg, newcfg) } - chainID := (*big.Int)(Get[*ChainID](cfg)) - newChainID := (*big.Int)(Get[*ChainID](newcfg)) - if cfg.Active(forks.TangerineWhistle, num, time) && !configBlockEqual(chainID, newChainID) { + if cfg.Active(forks.TangerineWhistle, num, time) && !configBlockEqual(ChainID.Get(cfg), ChainID.Get(newcfg)) { return newBlockCompatError2("EIP158 chain ID", forks.TangerineWhistle, cfg, newcfg) } diff --git a/params/registry.go b/params/registry.go index 1fd71c7179..17dc838a67 100644 --- a/params/registry.go +++ b/params/registry.go @@ -18,72 +18,78 @@ package params import ( "fmt" - "reflect" ) -type ParameterType interface{ - Validate(*Config2) error +type Parameter[V any] struct{ + info regInfo } -type paramInfo struct { - rtype reflect.Type - name string - optional bool - defaultVal ParameterType +func (p Parameter[V]) Get(cfg *Config2) V { + v, ok := cfg.param[p.info.id] + if ok { + return v.(V) + } + return p.info.defaultValue.(V) +} + +func (p Parameter[V]) V(v V) ParamValue { + return ParamValue{p.info.id, v} +} + +type ParamValue struct{ + id int + value any } var ( - paramRegistry = map[reflect.Type]*paramInfo{} - paramRegistryByName = map[string]*paramInfo{} + paramCounter int + paramRegistry = map[int]regInfo{} + paramRegistryByName = map[string]int{} ) -// Get retrieves the value of a chain parameter. -func Get[T ParameterType](cfg *Config2) T { - for _, p := range cfg.param { - if v, ok := p.(T); ok { - return v - } - } - // get default - var z T - info, ok := findParam(z) - if !ok { - panic(fmt.Sprintf("unknown parameter type %T", z)) - } - return info.defaultVal.(T) +type T[V any] struct{ + Name string + Optional bool + Default V + Validate func(v V, cfg *Config2) error } -// Parameter is the definition of a chain parameter. -type Parameter[T ParameterType] struct { - Name string - Optional bool - Default T +type regInfo struct{ + id int + name string + optional bool + defaultValue any + new func() any + validate func(any, *Config2) error } // Define creates a chain parameter in the registry. -func Define[T ParameterType](def Parameter[T]) { - var z T - info, defined := paramRegistryByName[def.Name] - if defined { - panic(fmt.Sprintf("chain parameter %q already registered with type %v", info.name, info.rtype)) +func Define[V any](def T[V]) Parameter[V] { + if id, defined := paramRegistryByName[def.Name]; defined { + info := paramRegistry[id] + panic(fmt.Sprintf("chain parameter %q already registered with type %T", def.Name, info.defaultValue)) } - rtype := reflect.TypeOf(z) - info, defined = paramRegistry[rtype] - if defined { - panic(fmt.Sprintf("chain parameter of type %v already registered with name %q", rtype, info.name)) - } - info = ¶mInfo{ - rtype: rtype, - name: def.Name, - optional: def.Optional, - defaultVal: def.Default, - } - paramRegistry[rtype] = info - paramRegistryByName[def.Name] = info -} -func findParam(v any) (*paramInfo, bool) { - rtype := reflect.TypeOf(v) - info, ok := paramRegistry[rtype] - return info, ok + id := paramCounter + paramCounter++ + + regInfo := regInfo{ + id: id, + name: def.Name, + optional: def.Optional, + defaultValue: def.Default, + new: func() any { + var z V + return z + }, + validate: func(v any, cfg *Config2) error { + if def.Validate == nil { + return nil + } + return def.Validate(v.(V), cfg) + }, + } + paramRegistry[id] = regInfo + paramRegistryByName[def.Name] = id + return Parameter[V]{info: regInfo} }