mirror of
https://github.com/luxfi/evm.git
synced 2026-09-24 00:27:44 +00:00
1106 lines
41 KiB
Go
1106 lines
41 KiB
Go
// (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 <http://www.gnu.org/licenses/>.
|
|
|
|
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,
|
|
}
|
|
}
|