// Copyright 2025 The go-ethereum Authors // This file is part of the go-ethereum library. // // The go-ethereum library is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // The go-ethereum library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . package params import ( "fmt" "strings" ) // Parameter represents a chain parameter. // Parameters are globally registered using `Define`. type Parameter[V any] struct { info regInfo } // Get retrieves the value of a parameter from a config. func (p Parameter[V]) Get(cfg *Config2) V { if p.info.id == 0 { panic("zero parameter") } v, ok := cfg.param[p.info.id] if ok { return v.(V) } return p.info.defaultValue.(V) } // V creates a ParamValue with the given value. You need this to // specify parameter values when constructing a Config in code. func (p Parameter[V]) V(v V) ParamValue { if p.info.id == 0 { panic("zero parameter") } return ParamValue{p.info.id, v} } // ParamValue contains a chain parameter and its value. // This is created by calling `V` on the parameter. type ParamValue struct { id int value any } var ( paramCounter = int(1) paramRegistry = map[int]regInfo{} paramRegistryByName = map[string]int{} ) // T is the definition of a chain parameter type. type T[V any] struct { Name string // the parameter name Optional bool // optional says 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. // This is meant to be called at package initialization time. func Define[V any](def T[V]) Parameter[V] { if def.Name == "" { panic("blank parameter name") } 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)) } if strings.HasSuffix(def.Name, "Block") || strings.HasSuffix(def.Name, "Time") { panic("chain parameter name cannot end in 'Block' or 'Time'") } 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} }