Files
2024-01-03 09:52:28 +01:00

911 lines
35 KiB
Go

// (c) 2021-2024, Lux Partners Limited.
//
// 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 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 (
"encoding/json"
"errors"
"fmt"
"math/big"
<<<<<<< HEAD
<<<<<<< HEAD
=======
"github.com/luxdefi/node/snow"
=======
"github.com/ethereum/go-ethereum/common"
>>>>>>> d5328b4 (Sync upstream)
"github.com/luxdefi/evm/commontype"
"github.com/luxdefi/evm/precompile/modules"
"github.com/luxdefi/evm/precompile/precompileconfig"
"github.com/luxdefi/evm/utils"
<<<<<<< HEAD
>>>>>>> fd08c47 (Update import path)
"github.com/ethereum/go-ethereum/common"
"github.com/luxdefi/node/snow"
"github.com/luxdefi/evm/commontype"
"github.com/luxdefi/evm/precompile/modules"
"github.com/luxdefi/evm/precompile/precompileconfig"
"github.com/luxdefi/evm/utils"
=======
"github.com/luxdefi/node/snow"
>>>>>>> d5328b4 (Sync upstream)
)
const maxJSONLen = 64 * 1024 * 1024 // 64MB
var (
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{
ChainID: EVMChainID,
FeeConfig: DefaultFeeConfig,
AllowFeeRecipients: false,
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),
MandatoryNetworkUpgrades: MainnetNetworkUpgrades, // This can be changed to correct network (local, test) via VM.
GenesisPrecompiles: Precompiles{},
}
TestChainConfig = &ChainConfig{
<<<<<<< HEAD
LuxContext: LuxContext{utils.TestSnowContext()},
=======
LuxContext: LuxContext{snow.DefaultContextTest()},
>>>>>>> d5328b4 (Sync upstream)
ChainID: big.NewInt(1),
FeeConfig: DefaultFeeConfig,
AllowFeeRecipients: false,
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),
MandatoryNetworkUpgrades: MandatoryNetworkUpgrades{
EVMTimestamp: utils.NewUint64(0),
DUpgradeTimestamp: utils.NewUint64(0),
},
GenesisPrecompiles: Precompiles{},
UpgradeConfig: UpgradeConfig{},
}
<<<<<<< HEAD
TestSubnetEVMConfig = &ChainConfig{
LuxContext: LuxContext{utils.TestSnowContext()},
=======
TestEVMConfig = &ChainConfig{
<<<<<<< HEAD
LuxContext: LuxContext{snow.DefaultContextTest()},
>>>>>>> fd08c47 (Update import path)
=======
LuxContext: LuxContext{snow.DefaultContextTest()},
>>>>>>> d5328b4 (Sync upstream)
ChainID: big.NewInt(1),
FeeConfig: DefaultFeeConfig,
AllowFeeRecipients: false,
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),
MandatoryNetworkUpgrades: MandatoryNetworkUpgrades{
EVMTimestamp: utils.NewUint64(0),
},
GenesisPrecompiles: Precompiles{},
UpgradeConfig: UpgradeConfig{},
}
<<<<<<< HEAD
TestPreSubnetEVMConfig = &ChainConfig{
LuxContext: LuxContext{utils.TestSnowContext()},
=======
TestPreEVMConfig = &ChainConfig{
<<<<<<< HEAD
LuxContext: LuxContext{snow.DefaultContextTest()},
>>>>>>> fd08c47 (Update import path)
=======
LuxContext: LuxContext{snow.DefaultContextTest()},
>>>>>>> d5328b4 (Sync upstream)
ChainID: big.NewInt(1),
FeeConfig: DefaultFeeConfig,
AllowFeeRecipients: false,
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),
MandatoryNetworkUpgrades: MandatoryNetworkUpgrades{},
GenesisPrecompiles: Precompiles{},
UpgradeConfig: UpgradeConfig{},
}
TestRules = TestChainConfig.LuxRules(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 *OptionalNetworkUpgrades `json:"networkUpgrades,omitempty"`
// Config for modifying state as a network upgrade.
StateUpgrades []StateUpgrade `json:"stateUpgrades,omitempty"`
// Config for enabling and disabling precompiles as network upgrades.
PrecompileUpgrades []PrecompileUpgrade `json:"precompileUpgrades,omitempty"`
}
// LuxContext provides Lux specific context directly into the EVM.
type LuxContext struct {
SnowCtx *snow.Context
}
// 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 {
LuxContext `json:"-"` // Lux specific context set during VM initialization. Not serialized.
ChainID *big.Int `json:"chainId"` // chainId identifies the current chain and is used for replay protection
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.
HomesteadBlock *big.Int `json:"homesteadBlock,omitempty"` // Homestead switch block (nil = no fork, 0 = already homestead)
// EIP150 implements the Gas price changes (https://github.com/ethereum/EIPs/issues/150)
EIP150Block *big.Int `json:"eip150Block,omitempty"` // EIP150 HF block (nil = no fork)
EIP155Block *big.Int `json:"eip155Block,omitempty"` // EIP155 HF block
EIP158Block *big.Int `json:"eip158Block,omitempty"` // EIP158 HF block
ByzantiumBlock *big.Int `json:"byzantiumBlock,omitempty"` // Byzantium switch block (nil = no fork, 0 = already on byzantium)
ConstantinopleBlock *big.Int `json:"constantinopleBlock,omitempty"` // Constantinople switch block (nil = no fork, 0 = already activated)
PetersburgBlock *big.Int `json:"petersburgBlock,omitempty"` // Petersburg switch block (nil = same as Constantinople)
IstanbulBlock *big.Int `json:"istanbulBlock,omitempty"` // Istanbul switch block (nil = no fork, 0 = already on istanbul)
MuirGlacierBlock *big.Int `json:"muirGlacierBlock,omitempty"` // Eip-2384 (bomb delay) switch block (nil = no fork, 0 = already activated)
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 json.
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)
}
// Description returns a human-readable description of ChainConfig.
func (c *ChainConfig) Description() string {
var banner string
banner += fmt.Sprintf("Chain ID: %v\n", c.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.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.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.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.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(" - EVM Timestamp: @%-10v (https://github.com/luxdefi/node/releases/tag/v1.10.0)\n", ptrToString(c.EVMTimestamp))
banner += fmt.Sprintf(" - DUpgrade Timestamp: @%-10v (https://github.com/luxdefi/node/releases/tag/v1.11.0)\n", ptrToString(c.DUpgradeTimestamp))
banner += fmt.Sprintf(" - Cancun Timestamp: @%-10v (https://github.com/luxdefi/node/releases/tag/v1.11.0)\n", ptrToString(c.CancunTime))
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
}
// 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.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.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.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.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.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.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.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.PetersburgBlock, num) || c.PetersburgBlock == nil && utils.IsBlockForked(c.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.IstanbulBlock, num)
}
// IsEVM returns whether [time] represents a block
// with a timestamp after the EVM upgrade time.
func (c *ChainConfig) IsEVM(time uint64) bool {
return utils.IsTimestampForked(c.EVMTimestamp, time)
}
// IsDUpgrade returns whether [time] represents a block
// with a timestamp after the DUpgrade upgrade time.
func (c *ChainConfig) IsDUpgrade(time uint64) bool {
return utils.IsTimestampForked(c.DUpgradeTimestamp, time)
}
// IsCancun returns whether [time] represents a block
// with a timestamp after the Cancun upgrade time.
func (c *ChainConfig) IsCancun(time uint64) bool {
return utils.IsTimestampForked(c.CancunTime, time)
}
func (r *Rules) PredicatersExist() bool {
return len(r.Predicaters) > 0
}
func (r *Rules) PredicaterExists(addr common.Address) bool {
_, PredicaterExists := r.Predicaters[addr]
return PredicaterExists
}
// IsPrecompileEnabled returns whether precompile with [address] is enabled at [timestamp].
func (c *ChainConfig) IsPrecompileEnabled(address common.Address, timestamp uint64) bool {
config := c.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.HomesteadBlock},
{name: "eip150Block", block: c.EIP150Block},
{name: "eip155Block", block: c.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
}
// 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 config.
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.HomesteadBlock, newcfg.HomesteadBlock, height) {
return newBlockCompatError("Homestead fork block", c.HomesteadBlock, newcfg.HomesteadBlock)
}
if isForkBlockIncompatible(c.EIP150Block, newcfg.EIP150Block, height) {
return newBlockCompatError("EIP150 fork block", c.EIP150Block, newcfg.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.ChainID, newcfg.ChainID) {
return newBlockCompatError("EIP158 chain ID", c.EIP158Block, newcfg.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 {
return err
}
// 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{}
}
if err := c.getOptionalNetworkUpgrades().CheckOptionalCompatible(newOptionalNetworkUpgrades, time); err != nil {
return err
}
// Check that the precompiles on the new config are compatible with the existing precompile config.
if err := c.CheckPrecompilesCompatible(newcfg.PrecompileUpgrades, time); err != nil {
return err
}
// Check that the state upgrades on the new config are compatible with the existing state upgrade config.
if err := c.CheckStateUpgradesCompatible(newcfg.StateUpgrades, time); err != nil {
return err
}
// 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 config.
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 block.
//
// 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
IsCancun bool
// Rules for Lux releases
IsEVM bool
IsDUpgrade 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 map addresses to stateful precompile accepter functions
// that are enabled for this rule set.
AccepterPrecompiles map[common.Address]precompileconfig.Accepter
}
// 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),
IsCancun: c.IsCancun(timestamp),
}
}
// LuxRules returns the Lux modified rules to support Lux
// network upgrades
func (c *ChainConfig) LuxRules(blockNum *big.Int, timestamp uint64) Rules {
rules := c.rules(blockNum, timestamp)
rules.IsEVM = c.IsEVM(timestamp)
rules.IsDUpgrade = c.IsDUpgrade(timestamp)
// Initialize the stateful precompiles that should be enabled at [blockTimestamp].
rules.ActivePrecompiles = make(map[common.Address]precompileconfig.Config)
rules.Predicaters = make(map[common.Address]precompileconfig.Predicater)
rules.AccepterPrecompiles = make(map[common.Address]precompileconfig.Accepter)
for _, module := range modules.RegisteredModules() {
if config := c.getActivePrecompileConfig(module.Address, timestamp); config != nil && !config.IsDisabled() {
rules.ActivePrecompiles[module.Address] = config
if predicater, ok := config.(precompileconfig.Predicater); ok {
rules.Predicaters[module.Address] = predicater
}
if precompileAccepter, ok := config.(precompileconfig.Accepter); ok {
rules.AccepterPrecompiles[module.Address] = precompileAccepter
}
}
}
return rules
}
// GetFeeConfig returns the original FeeConfig contained in the genesis ChainConfig.
// Implements precompile.ChainConfig interface.
func (c *ChainConfig) GetFeeConfig() commontype.FeeConfig {
return c.FeeConfig
}
// AllowedFeeRecipients returns the original AllowedFeeRecipients parameter contained in the genesis ChainConfig.
// Implements precompile.ChainConfig interface.
func (c *ChainConfig) AllowedFeeRecipients() bool {
return c.AllowFeeRecipients
}
type ChainConfigWithUpgradesJSON struct {
ChainConfig
UpgradeConfig UpgradeConfig `json:"upgrades,omitempty"`
}
// MarshalJSON implements json.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,
}
}