mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-24 13:46:43 +00:00
params: new param system
This commit is contained in:
parent
6b26791752
commit
b25e44a841
3 changed files with 103 additions and 168 deletions
|
|
@ -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)
|
||||
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",
|
||||
var DAOForkSupport = Define(T[bool]{
|
||||
Optional: true,
|
||||
Default: true,
|
||||
})
|
||||
Define(Parameter[BlobSchedule]{
|
||||
Name: "blobSchedule",
|
||||
Optional: true,
|
||||
})
|
||||
Define(Parameter[DepositContractAddress]{
|
||||
Name: "depositContractAddress",
|
||||
Optional: true,
|
||||
})
|
||||
}
|
||||
})
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
||||
// Parameter is the definition of a chain parameter.
|
||||
type Parameter[T ParameterType] struct {
|
||||
type T[V any] struct{
|
||||
Name string
|
||||
Optional bool
|
||||
Default T
|
||||
Default V
|
||||
Validate func(v V, cfg *Config2) error
|
||||
}
|
||||
|
||||
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,
|
||||
|
||||
id := paramCounter
|
||||
paramCounter++
|
||||
|
||||
regInfo := regInfo{
|
||||
id: id,
|
||||
name: def.Name,
|
||||
optional: def.Optional,
|
||||
defaultVal: def.Default,
|
||||
defaultValue: def.Default,
|
||||
new: func() any {
|
||||
var z V
|
||||
return z
|
||||
},
|
||||
validate: func(v any, cfg *Config2) error {
|
||||
if def.Validate == nil {
|
||||
return nil
|
||||
}
|
||||
paramRegistry[rtype] = info
|
||||
paramRegistryByName[def.Name] = info
|
||||
}
|
||||
|
||||
func findParam(v any) (*paramInfo, bool) {
|
||||
rtype := reflect.TypeOf(v)
|
||||
info, ok := paramRegistry[rtype]
|
||||
return info, ok
|
||||
return def.Validate(v.(V), cfg)
|
||||
},
|
||||
}
|
||||
paramRegistry[id] = regInfo
|
||||
paramRegistryByName[def.Name] = id
|
||||
return Parameter[V]{info: regInfo}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue