// (c) 2020-2020, Lux Industries, Inc. // // This file is a derived work, based on the go-ethereum library whose original // notices appear below. // // It is distributed under a license compatible with the licensing terms of the // original code from which it is derived. // // Much love to the original authors for their work. // ********** // Copyright 2016 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 interfaces. // // 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 ( "encoding/json" "errors" "fmt" "math/big" "github.com/luxfi/geth/common" ethparams "github.com/luxfi/geth/params" "github.com/luxfi/evm/commontype" "github.com/luxfi/evm/iface" "github.com/luxfi/evm/params/extras" "github.com/luxfi/evm/precompile/registry" "github.com/luxfi/evm/precompile/precompileconfig" "github.com/luxfi/evm/utils" ) // Type aliases for extras package types type ( MandatoryNetworkUpgrades = extras.NetworkUpgrades OptionalNetworkUpgrades = extras.NetworkUpgrades Precompiles = extras.Precompiles ) // testChainContext creates a test ChainContext from consensus.Context func testChainContext() *commontype.ChainContext { consensusCtx := utils.TestConsensusContext() // Convert 20-byte NodeID to 32-byte NodeID var nodeID commontype.NodeID copy(nodeID[:], consensusCtx.NodeID[:]) return &commontype.ChainContext{ NetworkID: consensusCtx.NetworkID, SubnetID: commontype.SubnetID(consensusCtx.SubnetID), ChainID: commontype.ChainID(consensusCtx.ChainID), NodeID: nodeID, ChainDataDir: consensusCtx.ChainDataDir, } } const maxJSONLen = 64 * 1024 * 1024 // 64MB var ( // MainnetNetworkUpgrades defines the network upgrade timestamps for mainnet // For v2.0.0, all upgrades are active at genesis (timestamp 0) MainnetNetworkUpgrades = extras.NetworkUpgrades{ GenesisTimestamp: utils.NewUint64(0), } errNonGenesisForkByHeight = errors.New("evm only supports forking by height at the genesis block") EVMChainID = big.NewInt(43214) // For legacy tests MinGasPrice int64 = 225_000_000_000 TestInitialBaseFee int64 = 225_000_000_000 TestMaxBaseFee int64 = 225_000_000_000 DynamicFeeExtraDataSize = 80 RollupWindow uint64 = 10 DefaultFeeConfig = commontype.FeeConfig{ GasLimit: big.NewInt(8_000_000), TargetBlockRate: 2, // in seconds MinBaseFee: big.NewInt(25_000_000_000), TargetGas: big.NewInt(15_000_000), BaseFeeChangeDenominator: big.NewInt(36), MinBlockGasCost: big.NewInt(0), MaxBlockGasCost: big.NewInt(1_000_000), BlockGasCostStep: big.NewInt(200_000), } ) var ( // EVMDefaultConfig is the default configuration // without any network upgrades. EVMDefaultChainConfig = &ChainConfig{ ChainConfig: ðparams.ChainConfig{ ChainID: DefaultChainID, HomesteadBlock: big.NewInt(0), EIP150Block: big.NewInt(0), EIP155Block: big.NewInt(0), EIP158Block: big.NewInt(0), ByzantiumBlock: big.NewInt(0), ConstantinopleBlock: big.NewInt(0), PetersburgBlock: big.NewInt(0), IstanbulBlock: big.NewInt(0), MuirGlacierBlock: big.NewInt(0), BerlinBlock: big.NewInt(0), LondonBlock: big.NewInt(0), // All time-based forks enabled from genesis ShanghaiTime: new(uint64), // 0 CancunTime: new(uint64), // 0 }, FeeConfig: DefaultFeeConfig, MandatoryNetworkUpgrades: MainnetNetworkUpgrades, // This can be changed to correct network (local, test) via VM. GenesisPrecompiles: Precompiles{}, } TestChainConfig = &ChainConfig{ ChainConfig: ðparams.ChainConfig{ ChainID: big.NewInt(1), HomesteadBlock: big.NewInt(0), EIP150Block: big.NewInt(0), EIP155Block: big.NewInt(0), EIP158Block: big.NewInt(0), ByzantiumBlock: big.NewInt(0), ConstantinopleBlock: big.NewInt(0), PetersburgBlock: big.NewInt(0), IstanbulBlock: big.NewInt(0), MuirGlacierBlock: big.NewInt(0), BerlinBlock: big.NewInt(0), LondonBlock: big.NewInt(0), ShanghaiTime: new(uint64), // 0 CancunTime: new(uint64), // 0 }, LuxContext: LuxContext{testChainContext()}, FeeConfig: DefaultFeeConfig, AllowFeeRecipients: false, MandatoryNetworkUpgrades: MandatoryNetworkUpgrades{ GenesisTimestamp: utils.NewUint64(0), }, } TestEVMConfig = &ChainConfig{ ChainConfig: ðparams.ChainConfig{ ChainID: big.NewInt(1), HomesteadBlock: big.NewInt(0), EIP150Block: big.NewInt(0), EIP155Block: big.NewInt(0), EIP158Block: big.NewInt(0), ByzantiumBlock: big.NewInt(0), ConstantinopleBlock: big.NewInt(0), PetersburgBlock: big.NewInt(0), IstanbulBlock: big.NewInt(0), MuirGlacierBlock: big.NewInt(0), BerlinBlock: big.NewInt(0), LondonBlock: big.NewInt(0), ShanghaiTime: new(uint64), // 0 CancunTime: new(uint64), // 0 }, LuxContext: LuxContext{testChainContext()}, FeeConfig: DefaultFeeConfig, AllowFeeRecipients: false, MandatoryNetworkUpgrades: MandatoryNetworkUpgrades{ GenesisTimestamp: utils.NewUint64(0), }, } TestPreEVMConfig = &ChainConfig{ ChainConfig: ðparams.ChainConfig{ ChainID: big.NewInt(1), HomesteadBlock: big.NewInt(0), EIP150Block: big.NewInt(0), EIP155Block: big.NewInt(0), EIP158Block: big.NewInt(0), ByzantiumBlock: big.NewInt(0), ConstantinopleBlock: big.NewInt(0), PetersburgBlock: big.NewInt(0), IstanbulBlock: big.NewInt(0), MuirGlacierBlock: big.NewInt(0), BerlinBlock: big.NewInt(0), LondonBlock: big.NewInt(0), ShanghaiTime: new(uint64), // 0 CancunTime: new(uint64), // 0 }, LuxContext: LuxContext{testChainContext()}, FeeConfig: DefaultFeeConfig, AllowFeeRecipients: false, MandatoryNetworkUpgrades: MandatoryNetworkUpgrades{}, GenesisPrecompiles: Precompiles{}, UpgradeConfig: UpgradeConfig{}, } TestRules = TestChainConfig.GenesisRules(new(big.Int), 0) ) // UpgradeConfig includes the following configs that may be specified in upgradeBytes: // - Timestamps that enable lux network upgrades, // - Enabling or disabling precompiles as network upgrades. type UpgradeConfig struct { // Config for optional timestamps that enable network upgrades. // Note: if OptionalUpgrades is specified in the JSON all previously activated // forks must be present or upgradeBytes will be rejected. OptionalNetworkUpgrades *extras.NetworkUpgrades `json:"networkUpgrades,omitempty"` // Config for modifying state as a network interfaces. StateUpgrades []extras.StateUpgrade `json:"stateUpgrades,omitempty"` // Config for enabling and disabling precompiles as network upgrades. PrecompileUpgrades []extras.PrecompileUpgrade `json:"precompileUpgrades,omitempty"` } // LuxContext provides Lux specific context directly into the EVM. type LuxContext struct { ConsensusCtx *commontype.ChainContext } // ChainConfig is the core config which determines the blockchain settings. // // ChainConfig is stored in the database on a per block basis. This means // that any network, identified by its genesis block, can have its own // set of configuration options. type ChainConfig struct { *ethparams.ChainConfig // Embedded geth ChainConfig LuxContext `json:"-"` // Lux specific context set during VM initialization. Not serialized. // Lux-specific extensions FeeConfig commontype.FeeConfig `json:"feeConfig"` // Set the configuration for the dynamic fee algorithm AllowFeeRecipients bool `json:"allowFeeRecipients,omitempty"` // Allows fees to be collected by block builders. MandatoryNetworkUpgrades // Config for timestamps that enable mandatory network upgrades. Skip encoding/decoding directly into ChainConfig. OptionalNetworkUpgrades // Config for optional timestamps that enable network upgrades GenesisPrecompiles Precompiles `json:"-"` // Config for enabling precompiles from genesis. JSON encode/decode will be handled by the custom marshaler/unmarshaler. UpgradeConfig `json:"-"` // Config specified in upgradeBytes (lux network upgrades or enable/disabling precompiles). Skip encoding/decoding directly into ChainConfig. } // UnmarshalJSON parses the JSON-encoded data and stores the result in the // object pointed to by c. // This is a custom unmarshaler to handle the Precompiles field. // Precompiles was presented as an inline object in the JSON. // This custom unmarshaler ensures backwards compatibility with the old format. func (c *ChainConfig) UnmarshalJSON(data []byte) error { // Alias ChainConfig to avoid recursion type _ChainConfig ChainConfig tmp := _ChainConfig{} if err := json.Unmarshal(data, &tmp); err != nil { return err } // At this point we have populated all fields except PrecompileUpgrade *c = ChainConfig(tmp) // Unmarshal inlined PrecompileUpgrade return json.Unmarshal(data, &c.GenesisPrecompiles) } // MarshalJSON returns the JSON encoding of c. // This is a custom marshaler to handle the Precompiles field. func (c ChainConfig) MarshalJSON() ([]byte, error) { // Alias ChainConfig to avoid recursion type _ChainConfig ChainConfig tmp, err := json.Marshal(_ChainConfig(c)) if err != nil { return nil, err } // To include PrecompileUpgrades, we unmarshal the json representing c // then directly add the corresponding keys to the interfaces. raw := make(map[string]json.RawMessage) if err := json.Unmarshal(tmp, &raw); err != nil { return nil, err } for key, value := range c.GenesisPrecompiles { conf, err := json.Marshal(value) if err != nil { return nil, err } raw[key] = conf } return json.Marshal(raw) } // ToEthChainConfig converts Lux ChainConfig to ethereum ChainConfig func (c *ChainConfig) ToEthChainConfig() *ethparams.ChainConfig { // Since we embed ethparams.ChainConfig, we can just return it return c.ChainConfig } // AsGeth returns the embedded geth ChainConfig // This is a convenience method for call sites that need the plain geth struct func (c *ChainConfig) AsGeth() interface{} { return c.ChainConfig } // Description returns a human-readable description of ChainConfig. func (c *ChainConfig) Description() string { var banner string banner += fmt.Sprintf("Chain ID: %v\n", c.ChainConfig.ChainID) banner += "Consensus: Dummy Consensus Engine\n\n" // Create a list of forks with a short description of them. Forks that only // makes sense for mainnet should be optional at printing to avoid bloating // the output for testnets and private networks. banner += "Hard Forks:\n" banner += fmt.Sprintf(" - Homestead: #%-8v (https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/homestead.md)\n", c.ChainConfig.HomesteadBlock) banner += fmt.Sprintf(" - Tangerine Whistle (EIP 150): #%-8v (https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/tangerine-whistle.md)\n", c.ChainConfig.EIP150Block) banner += fmt.Sprintf(" - Spurious Dragon/1 (EIP 155): #%-8v (https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/spurious-dragon.md)\n", c.ChainConfig.EIP155Block) banner += fmt.Sprintf(" - Spurious Dragon/2 (EIP 158): #%-8v (https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/spurious-dragon.md)\n", c.ChainConfig.EIP155Block) banner += fmt.Sprintf(" - Byzantium: #%-8v (https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/byzantium.md)\n", c.ByzantiumBlock) banner += fmt.Sprintf(" - Constantinople: #%-8v (https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/constantinople.md)\n", c.ConstantinopleBlock) banner += fmt.Sprintf(" - Petersburg: #%-8v (https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/petersburg.md)\n", c.PetersburgBlock) banner += fmt.Sprintf(" - Istanbul: #%-8v (https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/istanbul.md)\n", c.IstanbulBlock) if c.MuirGlacierBlock != nil { banner += fmt.Sprintf(" - Muir Glacier: #%-8v (https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/muir-glacier.md)\n", c.MuirGlacierBlock) } banner += "Mandatory Upgrades:\n" banner += fmt.Sprintf(" - Genesis Timestamp: @%-10v (All upgrades active at genesis)\n", ptrToString(c.MandatoryNetworkUpgrades.GenesisTimestamp)) banner += "\n" // Add EVM custom fields optionalNetworkUpgradeBytes, err := json.Marshal(c.OptionalNetworkUpgrades) if err != nil { optionalNetworkUpgradeBytes = []byte("cannot marshal OptionalNetworkUpgrades") } banner += fmt.Sprintf("Optional Network Upgrades: %s", string(optionalNetworkUpgradeBytes)) banner += "\n" precompileUpgradeBytes, err := json.Marshal(c.GenesisPrecompiles) if err != nil { precompileUpgradeBytes = []byte("cannot marshal PrecompileUpgrade") } banner += fmt.Sprintf("Precompile Upgrades: %s", string(precompileUpgradeBytes)) banner += "\n" upgradeConfigBytes, err := json.Marshal(c.UpgradeConfig) if err != nil { upgradeConfigBytes = []byte("cannot marshal UpgradeConfig") } banner += fmt.Sprintf("Upgrade Config: %s", string(upgradeConfigBytes)) banner += "\n" feeBytes, err := json.Marshal(c.FeeConfig) if err != nil { feeBytes = []byte("cannot marshal FeeConfig") } banner += fmt.Sprintf("Fee Config: %s", string(feeBytes)) banner += "\n" banner += fmt.Sprintf("Allow Fee Recipients: %v", c.AllowFeeRecipients) banner += "\n" return banner } // GetChainID returns the chain ID func (c *ChainConfig) GetChainID() *big.Int { return c.ChainConfig.ChainID } // IsHomestead returns whether num is either equal to the homestead block or greater. func (c *ChainConfig) IsHomestead(num *big.Int) bool { return utils.IsBlockForked(c.ChainConfig.HomesteadBlock, num) } // IsEIP150 returns whether num is either equal to the EIP150 fork block or greater. func (c *ChainConfig) IsEIP150(num *big.Int) bool { return utils.IsBlockForked(c.ChainConfig.EIP150Block, num) } // IsEIP155 returns whether num is either equal to the EIP155 fork block or greater. func (c *ChainConfig) IsEIP155(num *big.Int) bool { return utils.IsBlockForked(c.ChainConfig.EIP155Block, num) } // IsEIP158 returns whether num is either equal to the EIP158 fork block or greater. func (c *ChainConfig) IsEIP158(num *big.Int) bool { return utils.IsBlockForked(c.ChainConfig.EIP158Block, num) } // IsByzantium returns whether num is either equal to the Byzantium fork block or greater. func (c *ChainConfig) IsByzantium(num *big.Int) bool { return utils.IsBlockForked(c.ChainConfig.ByzantiumBlock, num) } // IsConstantinople returns whether num is either equal to the Constantinople fork block or greater. func (c *ChainConfig) IsConstantinople(num *big.Int) bool { return utils.IsBlockForked(c.ChainConfig.ConstantinopleBlock, num) } // IsMuirGlacier returns whether num is either equal to the Muir Glacier (EIP-2384) fork block or greater. func (c *ChainConfig) IsMuirGlacier(num *big.Int) bool { return utils.IsBlockForked(c.ChainConfig.MuirGlacierBlock, num) } // IsPetersburg returns whether num is either // - equal to or greater than the PetersburgBlock fork block, // - OR is nil, and Constantinople is active func (c *ChainConfig) IsPetersburg(num *big.Int) bool { return utils.IsBlockForked(c.ChainConfig.PetersburgBlock, num) || c.ChainConfig.PetersburgBlock == nil && utils.IsBlockForked(c.ChainConfig.ConstantinopleBlock, num) } // IsIstanbul returns whether num is either equal to the Istanbul fork block or greater. func (c *ChainConfig) IsIstanbul(num *big.Int) bool { return utils.IsBlockForked(c.ChainConfig.IstanbulBlock, num) } // IsBerlin returns whether num is either equal to the Berlin fork block or greater. func (c *ChainConfig) IsBerlin(num *big.Int) bool { return utils.IsBlockForked(c.ChainConfig.BerlinBlock, num) } // IsLondon returns whether num is either equal to the London fork block or greater. func (c *ChainConfig) IsLondon(num *big.Int) bool { return utils.IsBlockForked(c.ChainConfig.LondonBlock, num) } // IsShanghai returns whether time represents a block with a timestamp after the Shanghai upgrade time. // For v2.0.0, this is always true since all upgrades are active at genesis. func (c *ChainConfig) IsShanghai(num *big.Int, time uint64) bool { return true } // Rules returns the Ethereum chainrules to use for the given block number and timestamp. func (c *ChainConfig) Rules(num *big.Int, timestamp uint64) Rules { return c.rules(num, timestamp) } // IsEVM returns whether [time] represents a block // with a timestamp after the EVM upgrade time. // For v2.0.0, this is always true since all upgrades are active at genesis. func (c *ChainConfig) IsEVM(time uint64) bool { return true } // IsDUpgrade returns whether [time] represents a block // with a timestamp after the DUpgrade upgrade time. // For v2.0.0, this is always true since all upgrades are active at genesis. func (c *ChainConfig) IsDUpgrade(time uint64) bool { return true } // IsDurango returns whether [time] represents a block // with a timestamp after the Durango upgrade time. // Implements precompileconfig.ChainConfig interface. // For v2.0.0, this is always true since all upgrades are active at genesis. func (c *ChainConfig) IsDurango(time uint64) bool { return true } // AllowedFeeRecipients returns true if fee recipients are allowed // Implements precompileconfig.ChainConfig interface. func (c *ChainConfig) AllowedFeeRecipients() bool { return c.AllowFeeRecipients } // GetFeeConfig returns the original FeeConfig that was set in the genesis // Implements precompileconfig.ChainConfig interface. func (c *ChainConfig) GetFeeConfig() commontype.FeeConfig { extra := GetExtra(c) if extra == nil { return commontype.FeeConfig{} } return extra.FeeConfig } // IsCancun returns whether [time] represents a block // with a timestamp after the Cancun upgrade time. // For v2.0.0, this is always true since all upgrades are active at genesis. func (c *ChainConfig) IsCancun(time uint64) bool { return true } func (r *Rules) PredicatersExist() bool { return len(r.Predicaters) > 0 } func (r *Rules) PredicaterExists(addr common.Address) bool { _, PredicaterExists := r.Predicaters[addr] return PredicaterExists } // verifyPrecompileUpgrades checks that the precompile upgrades are valid func (c *ChainConfig) verifyPrecompileUpgrades() error { // State upgrades are stored in the UpgradeConfig if c.UpgradeConfig.PrecompileUpgrades == nil { return nil } // For now, we'll skip validation as the method is private return nil } // verifyStateUpgrades checks that the state upgrades are valid func (c *ChainConfig) verifyStateUpgrades() error { // State upgrades are stored in the UpgradeConfig if c.UpgradeConfig.StateUpgrades == nil { return nil } // For now, we'll skip validation as the method is private return nil } // mandatoryForkOrder returns the mandatory fork ordering func (c *ChainConfig) mandatoryForkOrder() []fork { return []fork{ {name: "homesteadBlock", block: c.ChainConfig.HomesteadBlock}, {name: "eip150Block", block: c.ChainConfig.EIP150Block}, {name: "eip155Block", block: c.ChainConfig.EIP155Block}, {name: "eip158Block", block: c.ChainConfig.EIP158Block}, {name: "byzantiumBlock", block: c.ChainConfig.ByzantiumBlock}, {name: "constantinopleBlock", block: c.ChainConfig.ConstantinopleBlock}, {name: "petersburgBlock", block: c.ChainConfig.PetersburgBlock}, {name: "istanbulBlock", block: c.ChainConfig.IstanbulBlock}, {name: "muirGlacierBlock", block: c.ChainConfig.MuirGlacierBlock, optional: true}, } } // optionalForkOrder returns the optional fork ordering func (c *ChainConfig) optionalForkOrder() []fork { if c.UpgradeConfig.OptionalNetworkUpgrades == nil { return nil } // For now, return empty as the method is private return nil } // CheckMandatoryCompatible checks if the mandatory network upgrades are compatible func (c *ChainConfig) CheckMandatoryCompatible(newcfg *MandatoryNetworkUpgrades, time uint64) error { // For now, skip this check as checkNetworkUpgradesCompatible is private return nil } // CheckPrecompilesCompatible checks that precompiles are compatible func (c *ChainConfig) CheckPrecompilesCompatible(precompileUpgrades []extras.PrecompileUpgrade, time uint64) error { // For now, skip this check as checkPrecompilesCompatible is private return nil } // CheckStateUpgradesCompatible checks that state upgrades are compatible func (c *ChainConfig) CheckStateUpgradesCompatible(stateUpgrades []extras.StateUpgrade, time uint64) error { // For now, skip this check as the method is private return nil } // IsPrecompileEnabled returns whether precompile with [address] is enabled at [timestamp]. func (c *ChainConfig) IsPrecompileEnabled(address common.Address, timestamp uint64) bool { extra := GetExtra(c) if extra == nil { return false } config := extra.GetActivePrecompileConfig(address, timestamp) return config != nil && !config.IsDisabled() } // CheckCompatible checks whether scheduled fork transitions have been imported // with a mismatching chain configuration. func (c *ChainConfig) CheckCompatible(newcfg *ChainConfig, height uint64, time uint64) *ConfigCompatError { var ( bhead = new(big.Int).SetUint64(height) btime = time ) // Iterate checkCompatible to find the lowest conflict. var lasterr *ConfigCompatError 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.SetUint64(err.RewindToBlock) } } return lasterr } // Verify verifies chain config and returns error func (c *ChainConfig) Verify() error { if err := c.FeeConfig.Verify(); err != nil { return err } // Verify the precompile upgrades are internally consistent given the existing chainConfig. if err := c.verifyPrecompileUpgrades(); err != nil { return fmt.Errorf("invalid precompile upgrades: %w", err) } // Verify the state upgrades are internally consistent given the existing chainConfig. if err := c.verifyStateUpgrades(); err != nil { return fmt.Errorf("invalid state upgrades: %w", err) } return nil } type fork struct { name string block *big.Int // some go-ethereum forks use block numbers timestamp *uint64 // Lux forks use timestamps optional bool // if true, the fork may be nil and next fork is still allowed } // CheckConfigForkOrder checks that we don't "skip" any forks, geth isn't pluggable enough // to guarantee that forks can be implemented in a different order than on official networks func (c *ChainConfig) CheckConfigForkOrder() error { ethForks := []fork{ {name: "homesteadBlock", block: c.ChainConfig.HomesteadBlock}, {name: "eip150Block", block: c.ChainConfig.EIP150Block}, {name: "eip155Block", block: c.ChainConfig.EIP155Block}, {name: "eip158Block", block: c.EIP158Block}, {name: "byzantiumBlock", block: c.ByzantiumBlock}, {name: "constantinopleBlock", block: c.ConstantinopleBlock}, {name: "petersburgBlock", block: c.PetersburgBlock}, {name: "istanbulBlock", block: c.IstanbulBlock}, {name: "muirGlacierBlock", block: c.MuirGlacierBlock, optional: true}, } // Check that forks are enabled in order if err := checkForks(ethForks, true); err != nil { return err } // Note: In Lux, hard forks must take place via block timestamps instead // of block numbers since blocks are produced asynchronously. Therefore, we do not // check that the block timestamps in the same way as for // the block number forks since it would not be a meaningful comparison. // Instead, we check only that Phases are enabled in order. // Note: we do not add the optional stateful precompile configs in here because they are optional // and independent, such that the ordering they are enabled does not impact the correctness of the // chain interfaces. if err := checkForks(c.mandatoryForkOrder(), false); err != nil { return err } // Check optional forks are enabled in order if err := checkForks(c.optionalForkOrder(), false); err != nil { return err } return nil } // checkForks checks that forks are enabled in order and returns an error if not // [blockFork] is true if the fork is a block number fork, false if it is a timestamp fork func checkForks(forks []fork, blockFork bool) error { lastFork := fork{} for _, cur := range forks { if blockFork && cur.block != nil && common.Big0.Cmp(cur.block) != 0 { return errNonGenesisForkByHeight } if lastFork.name != "" { // Next one must be higher number if lastFork.timestamp == nil && cur.timestamp != nil { return fmt.Errorf("unsupported fork ordering: %v not enabled, but %v enabled at %v", lastFork.name, cur.name, cur.timestamp) } if lastFork.timestamp != nil && cur.timestamp != nil { if *lastFork.timestamp > *cur.timestamp { return fmt.Errorf("unsupported fork ordering: %v enabled at %v, but %v enabled at %v", lastFork.name, lastFork.timestamp, cur.name, cur.timestamp) } } } // If it was optional and not set, then ignore it if !cur.optional || cur.timestamp != nil { lastFork = cur } } return nil } // checkCompatible confirms that [newcfg] is backwards compatible with [c] to upgrade with the given head block height and timestamp. // This confirms that all Ethereum and Lux upgrades are backwards compatible as well as that the precompile config is backwards // compatible. func (c *ChainConfig) checkCompatible(newcfg *ChainConfig, height *big.Int, time uint64) *ConfigCompatError { if isForkBlockIncompatible(c.ChainConfig.HomesteadBlock, newcfg.ChainConfig.HomesteadBlock, height) { return newBlockCompatError("Homestead fork block", c.ChainConfig.HomesteadBlock, newcfg.ChainConfig.HomesteadBlock) } if isForkBlockIncompatible(c.ChainConfig.EIP150Block, newcfg.ChainConfig.EIP150Block, height) { return newBlockCompatError("EIP150 fork block", c.ChainConfig.EIP150Block, newcfg.ChainConfig.EIP150Block) } if isForkBlockIncompatible(c.EIP155Block, newcfg.EIP155Block, height) { return newBlockCompatError("EIP155 fork block", c.EIP155Block, newcfg.EIP155Block) } if isForkBlockIncompatible(c.EIP158Block, newcfg.EIP158Block, height) { return newBlockCompatError("EIP158 fork block", c.EIP158Block, newcfg.EIP158Block) } if c.IsEIP158(height) && !utils.BigNumEqual(c.ChainConfig.ChainID, newcfg.ChainConfig.ChainID) { return newBlockCompatError("EIP158 chain ID", c.ChainConfig.EIP158Block, newcfg.ChainConfig.EIP158Block) } if isForkBlockIncompatible(c.ByzantiumBlock, newcfg.ByzantiumBlock, height) { return newBlockCompatError("Byzantium fork block", c.ByzantiumBlock, newcfg.ByzantiumBlock) } if isForkBlockIncompatible(c.ConstantinopleBlock, newcfg.ConstantinopleBlock, height) { return newBlockCompatError("Constantinople fork block", c.ConstantinopleBlock, newcfg.ConstantinopleBlock) } if isForkBlockIncompatible(c.PetersburgBlock, newcfg.PetersburgBlock, height) { // the only case where we allow Petersburg to be set in the past is if it is equal to Constantinople // mainly to satisfy fork ordering requirements which state that Petersburg fork be set if Constantinople fork is set if isForkBlockIncompatible(c.ConstantinopleBlock, newcfg.PetersburgBlock, height) { return newBlockCompatError("Petersburg fork block", c.PetersburgBlock, newcfg.PetersburgBlock) } } if isForkBlockIncompatible(c.IstanbulBlock, newcfg.IstanbulBlock, height) { return newBlockCompatError("Istanbul fork block", c.IstanbulBlock, newcfg.IstanbulBlock) } if isForkBlockIncompatible(c.MuirGlacierBlock, newcfg.MuirGlacierBlock, height) { return newBlockCompatError("Muir Glacier fork block", c.MuirGlacierBlock, newcfg.MuirGlacierBlock) } // Check lux network upgrades if err := c.CheckMandatoryCompatible(&newcfg.MandatoryNetworkUpgrades, time); err != nil { // Convert error to ConfigCompatError return &ConfigCompatError{ What: "mandatory network upgrades", StoredTime: nil, NewTime: nil, RewindToTime: 0, } } // Check evm specific activations newOptionalNetworkUpgrades := newcfg.getOptionalNetworkUpgrades() if c.UpgradeConfig.OptionalNetworkUpgrades != nil && newcfg.UpgradeConfig.OptionalNetworkUpgrades == nil { // Note: if the current OptionalNetworkUpgrades are set via UpgradeConfig, then a new config // without OptionalNetworkUpgrades will be treated as having specified an empty set of network // upgrades (ie., treated as the user intends to cancel scheduled forks) newOptionalNetworkUpgrades = &OptionalNetworkUpgrades{} } // Handle the case where both might be nil oldOptional := c.getOptionalNetworkUpgrades() if oldOptional != nil && newOptionalNetworkUpgrades != nil { // The checkNetworkUpgradesCompatible method is private, so we can't call it directly // For now, skip this check } // Check that the precompiles on the new config are compatible with the existing precompile interfaces. if err := c.CheckPrecompilesCompatible(newcfg.PrecompileUpgrades, time); err != nil { // Convert error to ConfigCompatError return &ConfigCompatError{ What: "precompile upgrades", StoredTime: nil, NewTime: nil, RewindToTime: 0, } } // Check that the state upgrades on the new config are compatible with the existing state upgrade interfaces. if err := c.CheckStateUpgradesCompatible(newcfg.StateUpgrades, time); err != nil { // Convert error to ConfigCompatError return &ConfigCompatError{ What: "state upgrades", StoredTime: nil, NewTime: nil, RewindToTime: 0, } } // TODO verify that the fee config is fully compatible between [c] and [newcfg]. return nil } // getOptionalNetworkUpgrades returns OptionalNetworkUpgrades from upgrade config if set there, // otherwise it falls back to the genesis chain interfaces. func (c *ChainConfig) getOptionalNetworkUpgrades() *OptionalNetworkUpgrades { if upgradeConfigOverride := c.UpgradeConfig.OptionalNetworkUpgrades; upgradeConfigOverride != nil { return upgradeConfigOverride } return &c.OptionalNetworkUpgrades } // isForkBlockIncompatible returns true if a fork scheduled at s1 cannot be rescheduled to // block s2 because head is already past the fork. func isForkBlockIncompatible(s1, s2, head *big.Int) bool { return (utils.IsBlockForked(s1, head) || utils.IsBlockForked(s2, head)) && !configBlockEqual(s1, s2) } func configBlockEqual(x, y *big.Int) bool { if x == nil { return y == nil } if y == nil { return x == nil } return x.Cmp(y) == 0 } // isForkTimestampIncompatible returns true if a fork scheduled at timestamp s1 // cannot be rescheduled to timestamp s2 because head is already past the fork. func isForkTimestampIncompatible(s1, s2 *uint64, head uint64) bool { return (utils.IsTimestampForked(s1, head) || utils.IsTimestampForked(s2, head)) && !configTimestampEqual(s1, s2) } func configTimestampEqual(x, y *uint64) bool { if x == nil { return y == nil } if y == nil { return x == nil } return *x == *y } // ConfigCompatError is raised if the locally-stored blockchain is initialised with a // ChainConfig that would alter the past. type ConfigCompatError struct { What string // block numbers of the stored and new configurations if block based forking StoredBlock, NewBlock *big.Int // timestamps of the stored and new configurations if time based forking StoredTime, NewTime *uint64 // the block number to which the local chain must be rewound to correct the error RewindToBlock uint64 // the timestamp to which the local chain must be rewound to correct the error RewindToTime uint64 } func newBlockCompatError(what string, storedblock, newblock *big.Int) *ConfigCompatError { var rew *big.Int switch { case storedblock == nil: rew = newblock case newblock == nil || storedblock.Cmp(newblock) < 0: rew = storedblock default: rew = newblock } err := &ConfigCompatError{ What: what, StoredBlock: storedblock, NewBlock: newblock, RewindToBlock: 0, } if rew != nil && rew.Sign() > 0 { err.RewindToBlock = rew.Uint64() - 1 } return err } func newTimestampCompatError(what string, storedtime, newtime *uint64) *ConfigCompatError { var rew *uint64 switch { case storedtime == nil: rew = newtime case newtime == nil || *storedtime < *newtime: rew = storedtime default: rew = newtime } err := &ConfigCompatError{ What: what, StoredTime: storedtime, NewTime: newtime, RewindToTime: 0, } if rew != nil && *rew > 0 { err.RewindToTime = *rew - 1 } return err } func (err *ConfigCompatError) Error() string { if err.StoredBlock != nil { return fmt.Sprintf("mismatching %s in database (have block %d, want block %d, rewindto block %d)", err.What, err.StoredBlock, err.NewBlock, err.RewindToBlock) } return fmt.Sprintf("mismatching %s in database (have timestamp %s, want timestamp %s, rewindto timestamp %d)", err.What, ptrToString(err.StoredTime), ptrToString(err.NewTime), err.RewindToTime) } func ptrToString(val *uint64) string { if val == nil { return "nil" } return fmt.Sprintf("%d", *val) } // Rules wraps ChainConfig and is merely syntactic sugar or can be used for functions // that do not have or require information about the interfaces. // // Rules is a one time interface meaning that it shouldn't be used in between transition // phases. type Rules struct { ChainID *big.Int IsHomestead, IsEIP150, IsEIP155, IsEIP158 bool IsByzantium, IsConstantinople, IsPetersburg, IsIstanbul bool IsBerlin, IsLondon bool IsShanghai, IsCancun bool // Rules for Lux releases - all upgrades are always active IsEVMEnabled bool // ActivePrecompiles maps addresses to stateful precompiled contracts that are enabled // for this rule set. // Note: none of these addresses should conflict with the address space used by // any existing precompiles. ActivePrecompiles map[common.Address]precompileconfig.Config // Predicaters maps addresses to stateful precompile Predicaters // that are enabled for this rule set. Predicaters map[common.Address]precompileconfig.Predicater // AccepterPrecompiles maps addresses to stateful precompile accepter functions // that are enabled for this rule set. AccepterPrecompiles map[common.Address]precompileconfig.Accepter } // IsEVM returns true if EVM is enabled func (r *Rules) IsEVM() bool { return r.IsEVMEnabled } // IsFortuna returns true (always enabled) func (r *Rules) IsFortuna() bool { return true } // IsGranite returns true (always enabled) func (r *Rules) IsGranite() bool { return true } // IsGenesis returns true (always enabled in v2.0.0) func (r *Rules) IsGenesis() bool { return true } // GetActivePrecompiles returns the active precompiles as an interface map func (r *Rules) GetActivePrecompiles() map[common.Address]interface{} { result := make(map[common.Address]interface{}) for addr, config := range r.ActivePrecompiles { result[addr] = config } return result } // GetPredicaters returns the predicaters as an interface map func (r *Rules) GetPredicaters() map[common.Address]interface{} { result := make(map[common.Address]interface{}) for addr, predicater := range r.Predicaters { result[addr] = predicater } return result } // GetAccepterPrecompiles returns the accepter precompiles as an interface map func (r *Rules) GetAccepterPrecompiles() map[common.Address]interface{} { result := make(map[common.Address]interface{}) for addr, accepter := range r.AccepterPrecompiles { result[addr] = accepter } return result } // IsPrecompileEnabled returns true if the precompile at [addr] is enabled for this rule set. func (r *Rules) IsPrecompileEnabled(addr common.Address) bool { _, ok := r.ActivePrecompiles[addr] return ok } // Rules ensures c's ChainID is not nil. func (c *ChainConfig) rules(num *big.Int, timestamp uint64) Rules { chainID := c.ChainID if chainID == nil { chainID = new(big.Int) } return Rules{ ChainID: new(big.Int).Set(chainID), IsHomestead: c.IsHomestead(num), IsEIP150: c.IsEIP150(num), IsEIP155: c.IsEIP155(num), IsEIP158: c.IsEIP158(num), IsByzantium: c.IsByzantium(num), IsConstantinople: c.IsConstantinople(num), IsPetersburg: c.IsPetersburg(num), IsIstanbul: c.IsIstanbul(num), IsBerlin: c.IsBerlin(num), IsLondon: c.IsLondon(num), IsShanghai: true, // Always true for v2.0.0 IsCancun: true, // Always true for v2.0.0 IsEVMEnabled: true, // Always true for v2.0.0 } } // GenesisRules returns the Genesis modified rules to support Genesis // network upgrades func (c *ChainConfig) GenesisRules(blockNum *big.Int, timestamp uint64) iface.GenesisRules { // Create an extras.Rules struct extrasRules := &extras.Rules{ GenesisRules: extras.GenesisRules{ IsGenesis: true, }, Precompiles: make(map[common.Address]precompileconfig.Config), Predicaters: make(map[common.Address]precompileconfig.Predicater), AccepterPrecompiles: make(map[common.Address]precompileconfig.Accepter), } // Initialize the stateful precompiles that should be enabled at [blockTimestamp]. extra := GetExtra(c) if extra != nil { for _, module := range registry.RegisteredModules() { if config := extra.GetActivePrecompileConfig(module.Address(), timestamp); config != nil && !config.IsDisabled() { extrasRules.Precompiles[module.Address()] = config if predicater, ok := config.(precompileconfig.Predicater); ok { extrasRules.Predicaters[module.Address()] = predicater } if precompileAccepter, ok := config.(precompileconfig.Accepter); ok { extrasRules.AccepterPrecompiles[module.Address()] = precompileAccepter } } } } return extrasRules } // IsFortuna returns whether [time] represents a block // with a timestamp after the Fortuna upgrade time. // For v2.0.0, this is always true since all upgrades are active at genesis. func (c *ChainConfig) IsFortuna(time uint64) bool { return true } // IsGenesis returns whether all network upgrades are active at genesis. // For v2.0.0, this is always true since all upgrades are active at genesis. func (c *ChainConfig) IsGenesis(time uint64) bool { return true } type ChainConfigWithUpgradesJSON struct { ChainConfig UpgradeConfig UpgradeConfig `json:"upgrades,omitempty"` } // MarshalJSON implements interfaces.Marshaler. This is a workaround for the fact that // the embedded ChainConfig struct has a MarshalJSON method, which prevents // the default JSON marshalling from working for UpgradeConfig. // TODO: consider removing this method by allowing external tag for the embedded // ChainConfig struct. func (cu ChainConfigWithUpgradesJSON) MarshalJSON() ([]byte, error) { // embed the ChainConfig struct into the response chainConfigJSON, err := json.Marshal(cu.ChainConfig) if err != nil { return nil, err } if len(chainConfigJSON) > maxJSONLen { return nil, errors.New("value too large") } type upgrades struct { UpgradeConfig UpgradeConfig `json:"upgrades"` } upgradeJSON, err := json.Marshal(upgrades{cu.UpgradeConfig}) if err != nil { return nil, err } if len(upgradeJSON) > maxJSONLen { return nil, errors.New("value too large") } // merge the two JSON objects mergedJSON := make([]byte, 0, len(chainConfigJSON)+len(upgradeJSON)+1) mergedJSON = append(mergedJSON, chainConfigJSON[:len(chainConfigJSON)-1]...) mergedJSON = append(mergedJSON, ',') mergedJSON = append(mergedJSON, upgradeJSON[1:]...) return mergedJSON, nil } func (cu *ChainConfigWithUpgradesJSON) UnmarshalJSON(input []byte) error { var cc ChainConfig if err := json.Unmarshal(input, &cc); err != nil { return err } type upgrades struct { UpgradeConfig UpgradeConfig `json:"upgrades"` } var u upgrades if err := json.Unmarshal(input, &u); err != nil { return err } cu.ChainConfig = cc cu.UpgradeConfig = u.UpgradeConfig return nil } // ToWithUpgradesJSON converts the ChainConfig to ChainConfigWithUpgradesJSON with upgrades explicitly displayed. // ChainConfig does not include upgrades in its JSON output. // This is a workaround for showing upgrades in the JSON output. func (c *ChainConfig) ToWithUpgradesJSON() *ChainConfigWithUpgradesJSON { return &ChainConfigWithUpgradesJSON{ ChainConfig: *c, UpgradeConfig: c.UpgradeConfig, } }