mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-24 13:46:43 +00:00
params: WIP config2
This commit is contained in:
parent
073e7ec4b0
commit
8cc54f2160
5 changed files with 732 additions and 29 deletions
58
params/chainparam.go
Normal file
58
params/chainparam.go
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
package params
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/params/forks"
|
||||
)
|
||||
|
||||
// ChainID
|
||||
type ChainID big.Int
|
||||
|
||||
// TerminalTotalDifficulty (TTD) is the total difficulty value where
|
||||
type TerminalTotalDifficulty big.Int
|
||||
|
||||
func (v *TerminalTotalDifficulty) MarshalText() ([]byte, error) {
|
||||
return (*big.Int)(v).MarshalText()
|
||||
}
|
||||
|
||||
func (v *TerminalTotalDifficulty) UnmarshalText(input []byte) error {
|
||||
return (*big.Int)(v).UnmarshalText(input)
|
||||
}
|
||||
|
||||
// DepositContractAddress configures the location of the deposit contract.
|
||||
type DepositContractAddress common.Address
|
||||
|
||||
// This configures the EIP-4844 parameters across forks.
|
||||
// There must be an entry for each fork
|
||||
type BlobSchedule map[forks.Fork]BlobConfig
|
||||
|
||||
// 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 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,
|
||||
})
|
||||
}
|
||||
373
params/config2.go
Normal file
373
params/config2.go
Normal file
|
|
@ -0,0 +1,373 @@
|
|||
// 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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
package params
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"maps"
|
||||
"math/big"
|
||||
"reflect"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"github.com/ethereum/go-ethereum/params/forks"
|
||||
)
|
||||
|
||||
// Activations contains the block numbers/timestamps where hard forks activate.
|
||||
type Activations map[forks.Fork]uint64
|
||||
|
||||
// Config2 represents the chain configuration.
|
||||
type Config2 struct {
|
||||
activation Activations
|
||||
param map[reflect.Type]ParameterType
|
||||
}
|
||||
|
||||
func NewConfig2(activations Activations, param ...ParameterType) *Config2 {
|
||||
cfg := &Config2{
|
||||
activation: maps.Clone(activations),
|
||||
param: make(map[reflect.Type]ParameterType, len(param)),
|
||||
}
|
||||
for _, pv := range param {
|
||||
info, ok := findParam(pv)
|
||||
if !ok {
|
||||
panic(fmt.Sprintf("undefined chain parameter type %T", pv))
|
||||
}
|
||||
cfg.param[info.rtype] = pv
|
||||
}
|
||||
return cfg
|
||||
}
|
||||
|
||||
// Active reports whether the given fork is active for a block number/time.
|
||||
func (cfg *Config2) Active(f forks.Fork, block, timestamp uint64) bool {
|
||||
activation, ok := cfg.activation[f]
|
||||
if f.BlockBased() {
|
||||
return ok && block >= activation
|
||||
}
|
||||
return ok && timestamp >= activation
|
||||
}
|
||||
|
||||
func (cfg *Config2) Activation(f forks.Fork) (uint64, bool) {
|
||||
a, ok := cfg.activation[f]
|
||||
return a, ok
|
||||
}
|
||||
|
||||
// Scheduled says whether the fork is scheduled at all.
|
||||
func (cfg *Config2) Scheduled(f forks.Fork) bool {
|
||||
_, ok := cfg.activation[f]
|
||||
return ok
|
||||
}
|
||||
|
||||
// SetActivations returns a new configuration with the given forks activated.
|
||||
func (cfg *Config2) SetActivations(forks Activations) *Config2 {
|
||||
newA := maps.Clone(cfg.activation)
|
||||
maps.Copy(newA, forks)
|
||||
return &Config2{activation: newA, param: cfg.param}
|
||||
}
|
||||
|
||||
// SetParam returns a new configuration with parameters modified.
|
||||
func (cfg *Config2) SetParam(p ParameterType) *Config2 {
|
||||
return &Config2{activation: cfg.activation}
|
||||
}
|
||||
|
||||
// LatestFork returns the latest time-based fork that would be active for the given time.
|
||||
func (cfg *Config2) LatestFork(time uint64) forks.Fork {
|
||||
londonBlock := cfg.activation[forks.London]
|
||||
for _, f := range slices.Backward(forks.CanonOrder) {
|
||||
if f.BlockBased() {
|
||||
break
|
||||
}
|
||||
if cfg.Active(f, londonBlock, time) {
|
||||
return f
|
||||
}
|
||||
}
|
||||
return forks.Paris
|
||||
}
|
||||
|
||||
// MarshalJSON encodes the config as JSON.
|
||||
func (cfg *Config2) MarshalJSON() ([]byte, error) {
|
||||
m := make(map[string]any)
|
||||
// params
|
||||
for _, p := range cfg.param {
|
||||
info, ok := findParam(p)
|
||||
if !ok {
|
||||
panic(fmt.Sprintf("unknown chain parameter %T", p))
|
||||
}
|
||||
m[info.name] = p
|
||||
}
|
||||
// forks
|
||||
for f, act := range cfg.activation {
|
||||
var name string
|
||||
if f.BlockBased() {
|
||||
name = fmt.Sprintf("%sBlock", strings.ToLower(name))
|
||||
} else {
|
||||
name = fmt.Sprintf("%sTime", strings.ToLower(name))
|
||||
}
|
||||
m[name] = act
|
||||
}
|
||||
return json.Marshal(m)
|
||||
}
|
||||
|
||||
// MarshalJSON encodes the config as JSON.
|
||||
func (cfg *Config2) UnmarshalJSON(input []byte) error {
|
||||
dec := json.NewDecoder(bytes.NewReader(input))
|
||||
tok, err := dec.Token()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if tok != json.Delim('{') {
|
||||
return fmt.Errorf("expected JSON object for chain configuration")
|
||||
}
|
||||
// Now we're in the object.
|
||||
newcfg := Config2{
|
||||
activation: make(Activations),
|
||||
}
|
||||
for {
|
||||
tok, err = dec.Token()
|
||||
if tok == json.Delim('}') {
|
||||
break
|
||||
} else if key, ok := tok.(string); ok {
|
||||
if strings.HasSuffix(key, "Block") || strings.HasSuffix(key, "Time") {
|
||||
err = newcfg.decodeActivation(key, dec)
|
||||
} else {
|
||||
err = newcfg.decodeParameter(key, dec)
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
*cfg = newcfg
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cfg *Config2) decodeActivation(key string, dec *json.Decoder) error {
|
||||
var num uint64
|
||||
if err := dec.Decode(&num); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var f forks.Fork
|
||||
name, ok := strings.CutSuffix(key, "Block")
|
||||
if ok {
|
||||
f, ok = forks.ByName(name)
|
||||
if !ok || !f.BlockBased() {
|
||||
return fmt.Errorf("unknown block-based fork %q", name)
|
||||
}
|
||||
} else if name, ok = strings.CutSuffix(key, "Time"); ok {
|
||||
f, ok = forks.ByName(name)
|
||||
if !ok || f.BlockBased() {
|
||||
return fmt.Errorf("unknown time-based fork %q", name)
|
||||
}
|
||||
}
|
||||
cfg.activation[f] = num
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cfg *Config2) decodeParameter(key string, dec *json.Decoder) error {
|
||||
info, ok := paramRegistryByName[key]
|
||||
if !ok {
|
||||
return fmt.Errorf("unknown chain parameter %q", key)
|
||||
}
|
||||
v := reflect.New(info.rtype).Interface()
|
||||
if err := dec.Decode(v); err != nil {
|
||||
return err
|
||||
}
|
||||
cfg.param[info.rtype] = v
|
||||
return nil
|
||||
}
|
||||
|
||||
// Validate checks the configuration to ensure forks are scheduled in order,
|
||||
// and required settings are present.
|
||||
func (cfg *Config2) Validate() error {
|
||||
sanityCheckCanonOrder()
|
||||
|
||||
lastFork := forks.CanonOrder[0]
|
||||
for _, f := range forks.CanonOrder[1:] {
|
||||
act := "timestamp"
|
||||
if f.BlockBased() {
|
||||
act = "block"
|
||||
}
|
||||
|
||||
switch {
|
||||
// Non-optional forks must all be present in the chain config up to the last defined fork.
|
||||
case !cfg.Scheduled(lastFork) && cfg.Scheduled(f):
|
||||
return fmt.Errorf("unsupported fork ordering: %v not enabled, but %v enabled at %s %v", lastFork, f, act, cfg.activation[f])
|
||||
|
||||
// Fork (whether defined by block or timestamp) must follow the fork definition sequence.
|
||||
case cfg.Scheduled(lastFork) && cfg.Scheduled(f):
|
||||
// Timestamp based forks can follow block based ones, but not the other way around.
|
||||
if !lastFork.BlockBased() && f.BlockBased() {
|
||||
return fmt.Errorf("unsupported fork ordering: %v used timestamp ordering, but %v reverted to block ordering", lastFork, f)
|
||||
}
|
||||
if lastFork.BlockBased() == f.BlockBased() && cfg.activation[lastFork] > cfg.activation[f] {
|
||||
return fmt.Errorf("unsupported fork ordering: %v enabled at %s %v, but %v enabled at %s %v", lastFork, act, cfg.activation[lastFork], f, act, cfg.activation[f])
|
||||
}
|
||||
}
|
||||
|
||||
// If it was optional and not set, then ignore it.
|
||||
if !f.Optional() || cfg.Scheduled(f) {
|
||||
lastFork = f
|
||||
}
|
||||
|
||||
// Check that all forks with blobs explicitly define the blob schedule configuration.
|
||||
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)
|
||||
}
|
||||
if defined {
|
||||
if err := bcfg.validate(); err != nil {
|
||||
return fmt.Errorf("invalid chain configuration in blobSchedule for fork %q: %v", f, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// CheckCompatible validates chain configuration changes.
|
||||
// This called before applying changes to the 'stored configuration', the config
|
||||
// which is held in the database. The given block number and time represent the current head
|
||||
// of the chain in that database.
|
||||
//
|
||||
// An error is returned when the new configuration attempts to schedule a fork below the
|
||||
// current chain head. The error contains enough information to rewind the chain to a
|
||||
// point where the new config can be applied safely.
|
||||
func (c *Config2) CheckCompatible(newcfg *Config2, blocknum uint64, time uint64) *ConfigCompatError {
|
||||
sanityCheckCanonOrder()
|
||||
|
||||
// Iterate checkCompatible to find the lowest conflict.
|
||||
var lasterr *ConfigCompatError
|
||||
bhead, btime := blocknum, time
|
||||
for {
|
||||
err := c.checkCompatible(newcfg, bhead, btime)
|
||||
if err == nil || (lasterr != nil && err.RewindToBlock == lasterr.RewindToBlock && err.RewindToTime == lasterr.RewindToTime) {
|
||||
break
|
||||
}
|
||||
lasterr = err
|
||||
|
||||
if err.RewindToTime > 0 {
|
||||
btime = err.RewindToTime
|
||||
} else {
|
||||
bhead = err.RewindToBlock
|
||||
}
|
||||
}
|
||||
return lasterr
|
||||
}
|
||||
|
||||
// checkCompatible checks config compatibility at a specific block height.
|
||||
func (cfg *Config2) checkCompatible(newcfg *Config2, num uint64, time uint64) *ConfigCompatError {
|
||||
incompatible := func(f forks.Fork) bool {
|
||||
return (cfg.Active(f, num, time) || newcfg.Active(f, num, time)) && !activationEqual(f, cfg, newcfg)
|
||||
}
|
||||
|
||||
for _, f := range forks.CanonOrder[1:] {
|
||||
if incompatible(f) {
|
||||
if f.BlockBased() {
|
||||
return newBlockCompatError2(fmt.Sprintf("%v fork block", f), f, cfg, newcfg)
|
||||
}
|
||||
return newTimestampCompatError2("%v fork timestamp", f, cfg, newcfg)
|
||||
}
|
||||
// Specialty checks:
|
||||
if cfg.Active(forks.DAO, num, time) && Get[DAOForkSupport](cfg) != Get[DAOForkSupport](newcfg) {
|
||||
return newBlockCompatError2("DAO fork support flag", f, cfg, newcfg)
|
||||
}
|
||||
chainID := (*big.Int)(Get[*ChainID](cfg))
|
||||
newChainID := (*big.Int)(Get[*ChainID](newcfg))
|
||||
if cfg.Active(forks.TangerineWhistle, num, time) && !configBlockEqual(chainID, newChainID) {
|
||||
return newBlockCompatError2("EIP158 chain ID", f, cfg, newcfg)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func newBlockCompatError2(what string, f forks.Fork, storedcfg, newcfg *Config2) *ConfigCompatError {
|
||||
err := &ConfigCompatError{What: what}
|
||||
if storedcfg.Scheduled(f) {
|
||||
err.StoredBlock = new(big.Int).SetUint64(storedcfg.activation[f])
|
||||
}
|
||||
if newcfg.Scheduled(f) {
|
||||
err.NewBlock = new(big.Int).SetUint64(newcfg.activation[f])
|
||||
}
|
||||
// Need to rewind to one block before the earliest possible activation.
|
||||
rew, _ := minActivation(f, storedcfg, newcfg)
|
||||
if rew > 0 {
|
||||
err.RewindToBlock = rew - 1
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func newTimestampCompatError2(what string, f forks.Fork, storedcfg, newcfg *Config2) *ConfigCompatError {
|
||||
err := &ConfigCompatError{What: what}
|
||||
if storedcfg.Scheduled(f) {
|
||||
t := storedcfg.activation[f]
|
||||
err.StoredTime = &t
|
||||
}
|
||||
if newcfg.Scheduled(f) {
|
||||
t := newcfg.activation[f]
|
||||
err.NewTime = &t
|
||||
}
|
||||
// Need to rewind to before the earliest possible activation.
|
||||
rew, _ := minActivation(f, storedcfg, newcfg)
|
||||
if rew > 0 {
|
||||
err.RewindToTime = rew - 1
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// minActivation the earliest possible activation block/time for the given fork
|
||||
// across two configurations.
|
||||
func minActivation(f forks.Fork, cfg1, cfg2 *Config2) (act uint64, scheduled bool) {
|
||||
switch {
|
||||
case !cfg1.Scheduled(f):
|
||||
act, scheduled = cfg2.activation[f]
|
||||
case !cfg2.Scheduled(f):
|
||||
act, scheduled = cfg1.activation[f]
|
||||
default:
|
||||
act = min(cfg1.activation[f], cfg2.activation[f])
|
||||
scheduled = true
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// activationEqual checks whether a fork has the same activation two configurations.
|
||||
// Note this also returns true when it isn't scheduled at all.
|
||||
func activationEqual(f forks.Fork, cfg1, cfg2 *Config2) bool {
|
||||
return cfg1.Scheduled(f) == cfg2.Scheduled(f) && cfg1.activation[f] == cfg2.activation[f]
|
||||
}
|
||||
|
||||
// sanityCheckCanonOrder verifies forks.CanonOrder is defined sensibly.
|
||||
// This exists to ensure library code doesn't mess with this slice in an incompatible way.
|
||||
func sanityCheckCanonOrder() {
|
||||
if len(forks.CanonOrder) == 0 {
|
||||
panic("forks.CanonOrder is empty")
|
||||
}
|
||||
if forks.CanonOrder[0] != forks.Frontier {
|
||||
panic("forks.CanonOrder must start with Frontier")
|
||||
}
|
||||
}
|
||||
|
||||
func cloneBig(x *big.Int) *big.Int {
|
||||
if x == nil {
|
||||
return nil
|
||||
}
|
||||
return new(big.Int).Set(x)
|
||||
}
|
||||
115
params/config2_presets.go
Normal file
115
params/config2_presets.go
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
// 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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
package params
|
||||
|
||||
import (
|
||||
"math"
|
||||
"math/big"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/params/forks"
|
||||
)
|
||||
|
||||
var (
|
||||
MainnetConfig2 *Config2
|
||||
AllEthashProtocolChanges2 *Config2
|
||||
MergedTestChainConfig2 *Config2
|
||||
)
|
||||
|
||||
func init() {
|
||||
MainnetConfig2 = NewConfig2(
|
||||
Activations{
|
||||
forks.Homestead: 1_150_000,
|
||||
forks.DAO: 1_920_000,
|
||||
forks.TangerineWhistle: 2_463_000,
|
||||
forks.SpuriousDragon: 2_675_000,
|
||||
forks.Byzantium: 4_370_000,
|
||||
forks.Constantinople: 7_280_000,
|
||||
forks.Petersburg: 7_280_000,
|
||||
forks.Istanbul: 9_069_000,
|
||||
forks.MuirGlacier: 9_200_000,
|
||||
forks.Berlin: 12_244_000,
|
||||
forks.London: 12_965_000,
|
||||
forks.ArrowGlacier: 13_773_000,
|
||||
forks.GrayGlacier: 15_050_000,
|
||||
// time-based forks
|
||||
forks.Shanghai: 1681338455,
|
||||
forks.Cancun: 1710338135,
|
||||
forks.Prague: 1746612311,
|
||||
},
|
||||
(*ChainID)(big.NewInt(1)),
|
||||
(*TerminalTotalDifficulty)(MainnetTerminalTotalDifficulty),
|
||||
DepositContractAddress(common.HexToAddress("0x00000000219ab540356cbb839cbe05303d7705fa")),
|
||||
DAOForkSupport(true),
|
||||
BlobSchedule{
|
||||
forks.Cancun: *DefaultCancunBlobConfig,
|
||||
forks.Prague: *DefaultPragueBlobConfig,
|
||||
},
|
||||
)
|
||||
|
||||
// AllEthashProtocolChanges2 contains every protocol change (EIPs) introduced
|
||||
// and accepted by the Ethereum core developers into the Ethash consensus.
|
||||
AllEthashProtocolChanges2 = NewConfig2(
|
||||
Activations{
|
||||
forks.Homestead: 0,
|
||||
forks.TangerineWhistle: 0,
|
||||
forks.SpuriousDragon: 0,
|
||||
forks.Byzantium: 0,
|
||||
forks.Constantinople: 0,
|
||||
forks.Petersburg: 0,
|
||||
forks.Istanbul: 0,
|
||||
forks.MuirGlacier: 0,
|
||||
forks.Berlin: 0,
|
||||
forks.London: 0,
|
||||
forks.ArrowGlacier: 0,
|
||||
forks.GrayGlacier: 0,
|
||||
},
|
||||
(*ChainID)(big.NewInt(1337)),
|
||||
(*TerminalTotalDifficulty)(big.NewInt(math.MaxInt64)),
|
||||
)
|
||||
|
||||
// MergedTestChainConfig2 contains every protocol change (EIPs) introduced
|
||||
// and accepted by the Ethereum core developers for testing purposes.
|
||||
MergedTestChainConfig2 = NewConfig2(
|
||||
Activations{
|
||||
forks.Homestead: 0,
|
||||
forks.TangerineWhistle: 0,
|
||||
forks.SpuriousDragon: 0,
|
||||
forks.Byzantium: 0,
|
||||
forks.Constantinople: 0,
|
||||
forks.Petersburg: 0,
|
||||
forks.Istanbul: 0,
|
||||
forks.MuirGlacier: 0,
|
||||
forks.Berlin: 0,
|
||||
forks.London: 0,
|
||||
forks.ArrowGlacier: 0,
|
||||
forks.GrayGlacier: 0,
|
||||
forks.Paris: 0,
|
||||
forks.Shanghai: 0,
|
||||
forks.Cancun: 0,
|
||||
forks.Prague: 0,
|
||||
forks.Osaka: 0,
|
||||
},
|
||||
(*ChainID)(big.NewInt(1)),
|
||||
(*TerminalTotalDifficulty)(big.NewInt(0)),
|
||||
BlobSchedule{
|
||||
forks.Cancun: *DefaultCancunBlobConfig,
|
||||
forks.Prague: *DefaultPragueBlobConfig,
|
||||
forks.Osaka: *DefaultOsakaBlobConfig,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
|
@ -16,60 +16,132 @@
|
|||
|
||||
package forks
|
||||
|
||||
import "fmt"
|
||||
|
||||
// Fork is a numerical identifier of specific network upgrades (forks).
|
||||
type Fork int
|
||||
type Fork uint32
|
||||
|
||||
const (
|
||||
Frontier Fork = iota
|
||||
FrontierThawing
|
||||
Homestead
|
||||
DAO
|
||||
TangerineWhistle // a.k.a. the EIP150 fork
|
||||
SpuriousDragon // a.k.a. the EIP155 fork
|
||||
Byzantium
|
||||
Constantinople
|
||||
Petersburg
|
||||
Istanbul
|
||||
MuirGlacier
|
||||
Berlin
|
||||
London
|
||||
ArrowGlacier
|
||||
GrayGlacier
|
||||
Paris
|
||||
Shanghai
|
||||
Cancun
|
||||
Prague
|
||||
Osaka
|
||||
Frontier Fork = iota | blockBased
|
||||
FrontierThawing Fork = iota | blockBased | optional
|
||||
Homestead Fork = iota | blockBased
|
||||
DAO Fork = iota | blockBased | optional
|
||||
TangerineWhistle Fork = iota | blockBased // a.k.a. the EIP150 fork
|
||||
SpuriousDragon Fork = iota | blockBased // a.k.a. the EIP155/EIP158 fork
|
||||
Byzantium Fork = iota | blockBased
|
||||
Constantinople Fork = iota | blockBased
|
||||
Petersburg Fork = iota | blockBased
|
||||
Istanbul Fork = iota | blockBased
|
||||
MuirGlacier Fork = iota | blockBased | optional
|
||||
Berlin Fork = iota | blockBased
|
||||
London Fork = iota | blockBased
|
||||
ArrowGlacier Fork = iota | blockBased | optional
|
||||
GrayGlacier Fork = iota | blockBased | optional
|
||||
Paris Fork = iota | blockBased | ismerge
|
||||
Shanghai Fork = iota
|
||||
Cancun Fork = iota | hasBlobs
|
||||
Prague Fork = iota | hasBlobs
|
||||
Osaka Fork = iota | hasBlobs
|
||||
Verkle Fork = iota | optional
|
||||
)
|
||||
|
||||
var CanonOrder = []Fork{
|
||||
Frontier,
|
||||
FrontierThawing,
|
||||
Homestead,
|
||||
DAO,
|
||||
TangerineWhistle,
|
||||
SpuriousDragon,
|
||||
Byzantium,
|
||||
Constantinople,
|
||||
Petersburg,
|
||||
Istanbul,
|
||||
MuirGlacier,
|
||||
Berlin,
|
||||
London,
|
||||
ArrowGlacier,
|
||||
GrayGlacier,
|
||||
Paris,
|
||||
Shanghai,
|
||||
Cancun,
|
||||
Prague,
|
||||
Osaka,
|
||||
Verkle,
|
||||
}
|
||||
|
||||
const (
|
||||
// Config bits: these bits are set on specific fork enum values and encode metadata
|
||||
// about the fork.
|
||||
blockBased = 1 << 31
|
||||
ismerge = 1 << 30
|
||||
optional = 1 << 29
|
||||
hasBlobs = 1 << 28
|
||||
|
||||
// The config bits can be stripped using this bit mask.
|
||||
unconfigMask = ^Fork(0) >> 8
|
||||
)
|
||||
|
||||
// IsMerge returns true for the merge fork.
|
||||
func (f Fork) IsMerge() bool {
|
||||
return f&ismerge != 0
|
||||
}
|
||||
|
||||
// Optional reports whether the fork can be left out of the config.
|
||||
func (f Fork) Optional() bool {
|
||||
return f&optional != 0
|
||||
}
|
||||
|
||||
// BlockBased reports whether the fork is scheduled by block number instead of timestamp.
|
||||
// This is true for pre-merge forks.
|
||||
func (f Fork) BlockBased() bool {
|
||||
return f&blockBased != 0
|
||||
}
|
||||
|
||||
// HasBlobs reports whether the fork must have a corresponding blob count configuration.
|
||||
func (f Fork) HasBlobs() bool {
|
||||
return f&hasBlobs != 0
|
||||
}
|
||||
|
||||
// String implements fmt.Stringer.
|
||||
func (f Fork) String() string {
|
||||
s, ok := forkToString[f]
|
||||
if !ok {
|
||||
return "Unknown fork"
|
||||
return fmt.Sprintf("unknownFork(%#x)", f)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
var forkToString = map[Fork]string{
|
||||
Frontier: "Frontier",
|
||||
FrontierThawing: "Frontier Thawing",
|
||||
Homestead: "Homestead",
|
||||
DAO: "DAO",
|
||||
TangerineWhistle: "Tangerine Whistle",
|
||||
SpuriousDragon: "Spurious Dragon",
|
||||
DAO: "DAOFork",
|
||||
TangerineWhistle: "TangerineWhistle",
|
||||
SpuriousDragon: "SpuriousDragon",
|
||||
Byzantium: "Byzantium",
|
||||
Constantinople: "Constantinople",
|
||||
Petersburg: "Petersburg",
|
||||
Istanbul: "Istanbul",
|
||||
MuirGlacier: "Muir Glacier",
|
||||
MuirGlacier: "MuirGlacier",
|
||||
Berlin: "Berlin",
|
||||
London: "London",
|
||||
ArrowGlacier: "Arrow Glacier",
|
||||
GrayGlacier: "Gray Glacier",
|
||||
ArrowGlacier: "ArrowGlacier",
|
||||
GrayGlacier: "GrayGlacier",
|
||||
Paris: "Paris",
|
||||
Shanghai: "Shanghai",
|
||||
Cancun: "Cancun",
|
||||
Prague: "Prague",
|
||||
Osaka: "Osaka",
|
||||
}
|
||||
|
||||
var forkFromString = make(map[string]Fork, len(forkToString))
|
||||
|
||||
func init() {
|
||||
for f, name := range forkToString {
|
||||
forkFromString[name] = f
|
||||
}
|
||||
}
|
||||
|
||||
func ByName(name string) (Fork, bool) {
|
||||
f, ok := forkFromString[name]
|
||||
return f, ok
|
||||
}
|
||||
|
|
|
|||
85
params/registry.go
Normal file
85
params/registry.go
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
// 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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
package params
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
type ParameterType any
|
||||
|
||||
type paramInfo struct {
|
||||
rtype reflect.Type
|
||||
name string
|
||||
optional bool
|
||||
defaultVal any
|
||||
}
|
||||
|
||||
var (
|
||||
paramRegistry = map[reflect.Type]*paramInfo{}
|
||||
paramRegistryByName = map[string]*paramInfo{}
|
||||
)
|
||||
|
||||
type Parameter[T ParameterType] struct {
|
||||
Name string
|
||||
Optional bool
|
||||
Default T
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
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))
|
||||
}
|
||||
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
|
||||
}
|
||||
Loading…
Reference in a new issue