From face38b12e1d9eabb21ef66fe8a3c8ebe0746776 Mon Sep 17 00:00:00 2001 From: Ceyhun Onur Date: Wed, 14 Aug 2024 15:11:55 +0300 Subject: [PATCH] Params nits (#1280) * refactor params config * rename SetEVMUpgrades * rename file --------- Co-authored-by: Darioush Jalali --- core/blockchain_test.go | 3 +- core/state_processor_test.go | 3 +- internal/ethapi/api_test.go | 3 +- params/config.go | 217 ++++++------------ params/config_extra.go | 121 +++++++++- .../config_extra_test.go | 41 ++-- params/network_upgrades.go | 6 +- params/precompile_upgrade.go | 4 +- params/state_upgrade.go | 3 +- plugin/evm/vm.go | 2 +- plugin/evm/vm_test.go | 3 +- plugin/evm/vm_upgrade_bytes_test.go | 6 +- plugin/evm/vm_warp_test.go | 7 +- utils/fork.go | 72 ------ utils/numbers.go | 39 ++++ 15 files changed, 267 insertions(+), 263 deletions(-) rename utils/fork_test.go => params/config_extra_test.go (72%) delete mode 100644 utils/fork.go create mode 100644 utils/numbers.go diff --git a/core/blockchain_test.go b/core/blockchain_test.go index 0f6f6464b7..8fad072f9e 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -9,6 +9,7 @@ import ( "os" "testing" + "github.com/ava-labs/avalanchego/upgrade" "github.com/ava-labs/subnet-evm/consensus/dummy" "github.com/ava-labs/subnet-evm/core/rawdb" "github.com/ava-labs/subnet-evm/core/state" @@ -1216,7 +1217,7 @@ func TestEIP3651(t *testing.T) { funds = new(big.Int).Mul(common.Big1, big.NewInt(params.Ether)) gspec = &Genesis{ Config: params.TestChainConfig, - Timestamp: uint64(params.DefaultGenesisTime.Unix()), + Timestamp: uint64(upgrade.InitiallyActiveTime.Unix()), Alloc: GenesisAlloc{ addr1: {Balance: funds}, addr2: {Balance: funds}, diff --git a/core/state_processor_test.go b/core/state_processor_test.go index 867d5ca919..ad35b811bd 100644 --- a/core/state_processor_test.go +++ b/core/state_processor_test.go @@ -31,6 +31,7 @@ import ( "math/big" "testing" + "github.com/ava-labs/avalanchego/upgrade" "github.com/ava-labs/subnet-evm/consensus" "github.com/ava-labs/subnet-evm/consensus/dummy" "github.com/ava-labs/subnet-evm/consensus/misc/eip4844" @@ -111,7 +112,7 @@ func TestStateProcessorErrors(t *testing.T) { db = rawdb.NewMemoryDatabase() gspec = &Genesis{ Config: config, - Timestamp: uint64(params.DefaultGenesisTime.Unix()), + Timestamp: uint64(upgrade.InitiallyActiveTime.Unix()), Alloc: GenesisAlloc{ common.HexToAddress("0x71562b71999873DB5b286dF957af199Ec94617F7"): GenesisAccount{ Balance: big.NewInt(4000000000000000000), // 4 ether diff --git a/internal/ethapi/api_test.go b/internal/ethapi/api_test.go index 0332f4ae4b..2ceb8a8ba5 100644 --- a/internal/ethapi/api_test.go +++ b/internal/ethapi/api_test.go @@ -39,6 +39,7 @@ import ( "testing" "time" + "github.com/ava-labs/avalanchego/upgrade" "github.com/ava-labs/subnet-evm/accounts" "github.com/ava-labs/subnet-evm/commontype" "github.com/ava-labs/subnet-evm/consensus" @@ -1409,7 +1410,7 @@ func setupReceiptBackend(t *testing.T, genBlocks int) (*testBackend, []common.Ha Config: &config, ExcessBlobGas: new(uint64), BlobGasUsed: new(uint64), - Timestamp: uint64(params.DefaultGenesisTime.Unix()), + Timestamp: uint64(upgrade.InitiallyActiveTime.Unix()), Alloc: core.GenesisAlloc{ acc1Addr: {Balance: big.NewInt(params.Ether)}, acc2Addr: {Balance: big.NewInt(params.Ether)}, diff --git a/params/config.go b/params/config.go index e3b26775c2..30c967bd9b 100644 --- a/params/config.go +++ b/params/config.go @@ -28,10 +28,8 @@ package params import ( "encoding/json" - "errors" "fmt" "math/big" - "time" "github.com/ava-labs/avalanchego/upgrade" "github.com/ava-labs/avalanchego/utils/constants" @@ -42,44 +40,11 @@ import ( "github.com/ethereum/go-ethereum/common" ) -const maxJSONLen = 64 * 1024 * 1024 // 64MB - -var ( - errNonGenesisForkByHeight = errors.New("subnet-evm only supports forking by height at the genesis block") - - SubnetEVMChainID = 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 - - DefaultGenesisTime = upgrade.InitiallyActiveTime - - 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), - } - - InactiveUpgradeTime = time.Date(10000, time.December, 1, 0, 0, 0, 0, time.UTC) -) - var ( // SubnetEVMDefaultConfig is the default configuration // without any network upgrades. SubnetEVMDefaultChainConfig = &ChainConfig{ - ChainID: SubnetEVMChainID, + ChainID: DefaultChainID, FeeConfig: DefaultFeeConfig, AllowFeeRecipients: false, @@ -131,9 +96,9 @@ var ( IstanbulBlock: big.NewInt(0), MuirGlacierBlock: big.NewInt(0), NetworkUpgrades: NetworkUpgrades{ - SubnetEVMTimestamp: utils.TimeToNewUint64(InactiveUpgradeTime), - DurangoTimestamp: utils.TimeToNewUint64(InactiveUpgradeTime), - EtnaTimestamp: utils.TimeToNewUint64(InactiveUpgradeTime), + SubnetEVMTimestamp: utils.TimeToNewUint64(upgrade.UnscheduledActivationTime), + DurangoTimestamp: utils.TimeToNewUint64(upgrade.UnscheduledActivationTime), + EtnaTimestamp: utils.TimeToNewUint64(upgrade.UnscheduledActivationTime), }, GenesisPrecompiles: Precompiles{}, UpgradeConfig: UpgradeConfig{}, @@ -155,8 +120,8 @@ var ( MuirGlacierBlock: big.NewInt(0), NetworkUpgrades: NetworkUpgrades{ SubnetEVMTimestamp: utils.NewUint64(0), - DurangoTimestamp: utils.TimeToNewUint64(InactiveUpgradeTime), - EtnaTimestamp: utils.TimeToNewUint64(InactiveUpgradeTime), + DurangoTimestamp: utils.TimeToNewUint64(upgrade.UnscheduledActivationTime), + EtnaTimestamp: utils.TimeToNewUint64(upgrade.UnscheduledActivationTime), }, GenesisPrecompiles: Precompiles{}, UpgradeConfig: UpgradeConfig{}, @@ -179,7 +144,7 @@ var ( NetworkUpgrades: NetworkUpgrades{ SubnetEVMTimestamp: utils.NewUint64(0), DurangoTimestamp: utils.NewUint64(0), - EtnaTimestamp: utils.TimeToNewUint64(InactiveUpgradeTime), + EtnaTimestamp: utils.TimeToNewUint64(upgrade.UnscheduledActivationTime), }, GenesisPrecompiles: Precompiles{}, UpgradeConfig: UpgradeConfig{}, @@ -207,7 +172,6 @@ var ( GenesisPrecompiles: Precompiles{}, UpgradeConfig: UpgradeConfig{}, } - TestRules = TestChainConfig.Rules(new(big.Int), 0) ) @@ -232,9 +196,9 @@ type ChainConfig struct { 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) - // Cancun activates the Cancun upgrade from Ethereum. (nil = no fork, 0 = already activated) - CancunTime *uint64 `json:"cancunTime,omitempty"` - // Verkle activates the Verkle upgrade from Ethereum. (nil = no fork, 0 = already activated) + // Fork scheduling was switched from blocks to timestamps here + + CancunTime *uint64 `json:"cancunTime,omitempty"` // Cancun switch time (nil = no fork, 0 = already activated) VerkleTime *uint64 `json:"verkleTime,omitempty"` // Verkle switch time (nil = no fork, 0 = already on verkle) NetworkUpgrades // Config for timestamps that enable network upgrades. Skip encoding/decoding directly into ChainConfig. @@ -306,76 +270,59 @@ func (c *ChainConfig) Description() string { // 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) + return 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) + return 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) + return 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) + return 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) + return 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) + return 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) + return 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) + return isBlockForked(c.PetersburgBlock, num) || c.PetersburgBlock == nil && 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) + return isBlockForked(c.IstanbulBlock, num) } -// IsCancun returns whether [time] represents a block -// with a timestamp after the Cancun upgrade time. +// IsCancun returns whether time is either equal to the Cancun fork time or greater. func (c *ChainConfig) IsCancun(num *big.Int, time uint64) bool { - return utils.IsTimestampForked(c.CancunTime, time) + return isTimestampForked(c.CancunTime, time) } -// IsVerkle returns whether [time] represents a block -// with a timestamp after the Verkle upgrade time. +// IsVerkle returns whether time is either equal to the Verkle fork time or greater. func (c *ChainConfig) IsVerkle(num *big.Int, time uint64) bool { - return utils.IsTimestampForked(c.VerkleTime, 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() + return isTimestampForked(c.VerkleTime, time) } // CheckCompatible checks whether scheduled fork transitions have been imported @@ -403,30 +350,6 @@ func (c *ChainConfig) CheckCompatible(newcfg *ChainConfig, height uint64, time u 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) - } - - // Verify the network upgrades are internally consistent given the existing chainConfig. - if err := c.verifyNetworkUpgrades(c.SnowCtx.NetworkID); err != nil { - return fmt.Errorf("invalid network upgrades: %w", err) - } - - return nil -} - type fork struct { name string block *big.Int // some go-ethereum forks use block numbers @@ -447,7 +370,8 @@ func (c *ChainConfig) CheckConfigForkOrder() error { {name: "petersburgBlock", block: c.PetersburgBlock}, {name: "istanbulBlock", block: c.IstanbulBlock}, {name: "muirGlacierBlock", block: c.MuirGlacierBlock, optional: true}, - {name: "cancunTime", timestamp: c.CancunTime}, + {name: "cancunTime", timestamp: c.CancunTime, optional: true}, + {name: "verkleTime", timestamp: c.VerkleTime, optional: true}, } // Check that forks are enabled in order @@ -518,60 +442,60 @@ func checkForks(forks []fork, blockFork bool) error { // 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 Avalanche 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) { +func (c *ChainConfig) checkCompatible(newcfg *ChainConfig, headNumber *big.Int, headTimestamp uint64) *ConfigCompatError { + if isForkBlockIncompatible(c.HomesteadBlock, newcfg.HomesteadBlock, headNumber) { return newBlockCompatError("Homestead fork block", c.HomesteadBlock, newcfg.HomesteadBlock) } - if isForkBlockIncompatible(c.EIP150Block, newcfg.EIP150Block, height) { + if isForkBlockIncompatible(c.EIP150Block, newcfg.EIP150Block, headNumber) { return newBlockCompatError("EIP150 fork block", c.EIP150Block, newcfg.EIP150Block) } - if isForkBlockIncompatible(c.EIP155Block, newcfg.EIP155Block, height) { + if isForkBlockIncompatible(c.EIP155Block, newcfg.EIP155Block, headNumber) { return newBlockCompatError("EIP155 fork block", c.EIP155Block, newcfg.EIP155Block) } - if isForkBlockIncompatible(c.EIP158Block, newcfg.EIP158Block, height) { + if isForkBlockIncompatible(c.EIP158Block, newcfg.EIP158Block, headNumber) { return newBlockCompatError("EIP158 fork block", c.EIP158Block, newcfg.EIP158Block) } - if c.IsEIP158(height) && !utils.BigNumEqual(c.ChainID, newcfg.ChainID) { + if c.IsEIP158(headNumber) && !utils.BigNumEqual(c.ChainID, newcfg.ChainID) { return newBlockCompatError("EIP158 chain ID", c.EIP158Block, newcfg.EIP158Block) } - if isForkBlockIncompatible(c.ByzantiumBlock, newcfg.ByzantiumBlock, height) { + if isForkBlockIncompatible(c.ByzantiumBlock, newcfg.ByzantiumBlock, headNumber) { return newBlockCompatError("Byzantium fork block", c.ByzantiumBlock, newcfg.ByzantiumBlock) } - if isForkBlockIncompatible(c.ConstantinopleBlock, newcfg.ConstantinopleBlock, height) { + if isForkBlockIncompatible(c.ConstantinopleBlock, newcfg.ConstantinopleBlock, headNumber) { return newBlockCompatError("Constantinople fork block", c.ConstantinopleBlock, newcfg.ConstantinopleBlock) } - if isForkBlockIncompatible(c.PetersburgBlock, newcfg.PetersburgBlock, height) { + if isForkBlockIncompatible(c.PetersburgBlock, newcfg.PetersburgBlock, headNumber) { // 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) { + if isForkBlockIncompatible(c.ConstantinopleBlock, newcfg.PetersburgBlock, headNumber) { return newBlockCompatError("Petersburg fork block", c.PetersburgBlock, newcfg.PetersburgBlock) } } - if isForkBlockIncompatible(c.IstanbulBlock, newcfg.IstanbulBlock, height) { + if isForkBlockIncompatible(c.IstanbulBlock, newcfg.IstanbulBlock, headNumber) { return newBlockCompatError("Istanbul fork block", c.IstanbulBlock, newcfg.IstanbulBlock) } - if isForkBlockIncompatible(c.MuirGlacierBlock, newcfg.MuirGlacierBlock, height) { + if isForkBlockIncompatible(c.MuirGlacierBlock, newcfg.MuirGlacierBlock, headNumber) { return newBlockCompatError("Muir Glacier fork block", c.MuirGlacierBlock, newcfg.MuirGlacierBlock) } - if isForkTimestampIncompatible(c.CancunTime, newcfg.CancunTime, time) { - return newTimestampCompatError("Cancun fork block timestamp", c.CancunTime, c.CancunTime) + if isForkTimestampIncompatible(c.CancunTime, newcfg.CancunTime, headTimestamp) { + return newTimestampCompatError("Cancun fork timestamp", c.CancunTime, newcfg.CancunTime) } - if isForkTimestampIncompatible(c.VerkleTime, newcfg.VerkleTime, time) { - return newTimestampCompatError("Verkle fork block timestamp", c.VerkleTime, newcfg.VerkleTime) + if isForkTimestampIncompatible(c.VerkleTime, newcfg.VerkleTime, headTimestamp) { + return newTimestampCompatError("Verkle fork timestamp", c.VerkleTime, newcfg.VerkleTime) } // Check avalanche network upgrades - if err := c.CheckNetworkUpgradesCompatible(&newcfg.NetworkUpgrades, time); err != nil { + if err := c.CheckNetworkUpgradesCompatible(&newcfg.NetworkUpgrades, headTimestamp); 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 { + if err := c.CheckPrecompilesCompatible(newcfg.PrecompileUpgrades, headTimestamp); 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 { + if err := c.CheckStateUpgradesCompatible(newcfg.StateUpgrades, headTimestamp); err != nil { return err } @@ -579,10 +503,20 @@ func (c *ChainConfig) checkCompatible(newcfg *ChainConfig, height *big.Int, time return nil } -// isForkBlockIncompatible returns true if a fork scheduled at s1 cannot be rescheduled to -// block s2 because head is already past the fork. +// isForkBlockIncompatible returns true if a fork scheduled at block 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) + return (isBlockForked(s1, head) || isBlockForked(s2, head)) && !configBlockEqual(s1, s2) +} + +// isBlockForked returns whether a fork scheduled at block s is active at the +// given head block. Whilst this method is the same as isTimestampForked, they +// are explicitly separate for clearer reading. +func isBlockForked(s, head *big.Int) bool { + if s == nil || head == nil { + return false + } + return s.Cmp(head) <= 0 } func configBlockEqual(x, y *big.Int) bool { @@ -598,7 +532,17 @@ func configBlockEqual(x, y *big.Int) bool { // 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) + return (isTimestampForked(s1, head) || isTimestampForked(s2, head)) && !configTimestampEqual(s1, s2) +} + +// isTimestampForked returns whether a fork scheduled at timestamp s is active +// at the given head timestamp. Whilst this method is the same as isBlockForked, +// they are explicitly separate for clearer reading. +func isTimestampForked(s *uint64, head uint64) bool { + if s == nil { + return false + } + return *s <= head } func configTimestampEqual(x, y *uint64) bool { @@ -680,13 +624,6 @@ func (err *ConfigCompatError) Error() string { 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) -} - type EthRules struct { IsHomestead, IsEIP150, IsEIP155, IsEIP158 bool IsByzantium, IsConstantinople, IsPetersburg, IsIstanbul bool @@ -720,12 +657,6 @@ type Rules struct { 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 @@ -773,15 +704,3 @@ func (c *ChainConfig) Rules(blockNum *big.Int, timestamp uint64) Rules { 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 -} diff --git a/params/config_extra.go b/params/config_extra.go index 5182625e7e..012e57bca6 100644 --- a/params/config_extra.go +++ b/params/config_extra.go @@ -6,10 +6,45 @@ package params import ( "encoding/json" "errors" + "fmt" "math/big" "github.com/ava-labs/avalanchego/snow" + "github.com/ava-labs/subnet-evm/commontype" "github.com/ava-labs/subnet-evm/utils" + "github.com/ethereum/go-ethereum/common" +) + +const ( + maxJSONLen = 64 * 1024 * 1024 // 64MB + + // Consensus Params + RollupWindow uint64 = 10 + DynamicFeeExtraDataSize = 80 + + // For legacy tests + MinGasPrice int64 = 225_000_000_000 + TestInitialBaseFee int64 = 225_000_000_000 + TestMaxBaseFee int64 = 225_000_000_000 +) + +var ( + errNonGenesisForkByHeight = errors.New("subnet-evm only supports forking by height at the genesis block") + + DefaultChainID = big.NewInt(43214) + + 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), + } ) // UpgradeConfig includes the following configs that may be specified in upgradeBytes: @@ -31,6 +66,13 @@ type AvalancheContext struct { SnowCtx *snow.Context } +// SetEthUpgrades sets the mapped upgrades Avalanche > EVM upgrades) for the chain config. +func (c *ChainConfig) SetEthUpgrades(avalancheUpgrades NetworkUpgrades) { + if avalancheUpgrades.EtnaTimestamp != nil { + c.CancunTime = utils.NewUint64(*avalancheUpgrades.EtnaTimestamp) + } +} + // 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. @@ -138,6 +180,48 @@ func (cu *ChainConfigWithUpgradesJSON) UnmarshalJSON(input []byte) error { return nil } +// 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) + } + + // Verify the network upgrades are internally consistent given the existing chainConfig. + if err := c.verifyNetworkUpgrades(c.SnowCtx.NetworkID); err != nil { + return fmt.Errorf("invalid network upgrades: %w", err) + } + + return nil +} + +// 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() +} + +// 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 +} + // 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. @@ -180,9 +264,38 @@ func (c *ChainConfig) SetNetworkUpgradeDefaults() { c.NetworkUpgrades.setDefaults(c.SnowCtx.NetworkID) } -// SetEVMUpgrades sets the mapped upgrades Avalanche > EVM upgrades) for the chain config. -func (c *ChainConfig) SetEVMUpgrades(avalancheUpgrades NetworkUpgrades) { - if avalancheUpgrades.EtnaTimestamp != nil { - c.CancunTime = utils.NewUint64(*avalancheUpgrades.EtnaTimestamp) +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 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 +} + +func ptrToString(val *uint64) string { + if val == nil { + return "nil" + } + return fmt.Sprintf("%d", *val) +} + +// IsForkTransition returns true if [fork] activates during the transition from +// [parent] to [current]. +// Taking [parent] as a pointer allows for us to pass nil when checking forks +// that activate during genesis. +// Note: this works for both block number and timestamp activated forks. +func IsForkTransition(fork *uint64, parent *uint64, current uint64) bool { + var parentForked bool + if parent != nil { + parentForked = isTimestampForked(fork, *parent) } + currentForked := isTimestampForked(fork, current) + return !parentForked && currentForked } diff --git a/utils/fork_test.go b/params/config_extra_test.go similarity index 72% rename from utils/fork_test.go rename to params/config_extra_test.go index ec7870e813..2253c3dd8a 100644 --- a/utils/fork_test.go +++ b/params/config_extra_test.go @@ -1,11 +1,12 @@ -// (c) 2019-2020, Ava Labs, Inc. All rights reserved. +// (c) 2024 Ava Labs, Inc. All rights reserved. // See the file LICENSE for licensing terms. -package utils +package params import ( "testing" + "github.com/ava-labs/subnet-evm/utils" "github.com/stretchr/testify/assert" ) @@ -28,28 +29,28 @@ func TestIsTimestampForked(t *testing.T) { isForked: false, }, "zero fork at genesis": { - fork: NewUint64(0), + fork: utils.NewUint64(0), block: 0, isForked: true, }, "pre fork timestamp": { - fork: NewUint64(100), + fork: utils.NewUint64(100), block: 50, isForked: false, }, "at fork timestamp": { - fork: NewUint64(100), + fork: utils.NewUint64(100), block: 100, isForked: true, }, "post fork timestamp": { - fork: NewUint64(100), + fork: utils.NewUint64(100), block: 150, isForked: true, }, } { t.Run(name, func(t *testing.T) { - res := IsTimestampForked(test.fork, test.block) + res := isTimestampForked(test.fork, test.block) assert.Equal(t, test.isForked, res) }) } @@ -70,50 +71,50 @@ func TestIsForkTransition(t *testing.T) { transitioned: false, }, "activate at genesis": { - fork: NewUint64(0), + fork: utils.NewUint64(0), parent: nil, current: 0, transitioned: true, }, "nil fork arbitrary transition": { fork: nil, - parent: NewUint64(100), + parent: utils.NewUint64(100), current: 101, transitioned: false, }, "nil fork transition same timestamp": { fork: nil, - parent: NewUint64(100), + parent: utils.NewUint64(100), current: 100, transitioned: false, }, "exact match on current timestamp": { - fork: NewUint64(100), - parent: NewUint64(99), + fork: utils.NewUint64(100), + parent: utils.NewUint64(99), current: 100, transitioned: true, }, "current same as parent does not transition twice": { - fork: NewUint64(100), - parent: NewUint64(101), + fork: utils.NewUint64(100), + parent: utils.NewUint64(101), current: 101, transitioned: false, }, "current, parent, and fork same should not transition twice": { - fork: NewUint64(100), - parent: NewUint64(100), + fork: utils.NewUint64(100), + parent: utils.NewUint64(100), current: 100, transitioned: false, }, "current transitions after fork": { - fork: NewUint64(100), - parent: NewUint64(99), + fork: utils.NewUint64(100), + parent: utils.NewUint64(99), current: 101, transitioned: true, }, "current and parent come after fork": { - fork: NewUint64(100), - parent: NewUint64(101), + fork: utils.NewUint64(100), + parent: utils.NewUint64(101), current: 102, transitioned: false, }, diff --git a/params/network_upgrades.go b/params/network_upgrades.go index 920a5e71b6..e4956f96a7 100644 --- a/params/network_upgrades.go +++ b/params/network_upgrades.go @@ -103,19 +103,19 @@ func (n *NetworkUpgrades) Override(o *NetworkUpgrades) { // IsSubnetEVM returns whether [time] represents a block // with a timestamp after the SubnetEVM upgrade time. func (n *NetworkUpgrades) IsSubnetEVM(time uint64) bool { - return utils.IsTimestampForked(n.SubnetEVMTimestamp, time) + return isTimestampForked(n.SubnetEVMTimestamp, time) } // IsDurango returns whether [time] represents a block // with a timestamp after the Durango upgrade time. func (n *NetworkUpgrades) IsDurango(time uint64) bool { - return utils.IsTimestampForked(n.DurangoTimestamp, time) + return isTimestampForked(n.DurangoTimestamp, time) } // IsEtna returns whether [time] represents a block // with a timestamp after the Etna upgrade time. func (n *NetworkUpgrades) IsEtna(time uint64) bool { - return utils.IsTimestampForked(n.EtnaTimestamp, time) + return isTimestampForked(n.EtnaTimestamp, time) } func (n *NetworkUpgrades) Description() string { diff --git a/params/precompile_upgrade.go b/params/precompile_upgrade.go index 3f762f96c4..f4985dc9ec 100644 --- a/params/precompile_upgrade.go +++ b/params/precompile_upgrade.go @@ -170,7 +170,7 @@ func (c *ChainConfig) GetActivatingPrecompileConfigs(address common.Address, fro // First check the embedded [upgrade] for precompiles configured // in the genesis chain config. if config, ok := c.GenesisPrecompiles[key]; ok { - if utils.IsForkTransition(config.Timestamp(), from, to) { + if IsForkTransition(config.Timestamp(), from, to) { configs = append(configs, config) } } @@ -178,7 +178,7 @@ func (c *ChainConfig) GetActivatingPrecompileConfigs(address common.Address, fro for _, upgrade := range upgrades { if upgrade.Key() == key { // Check if the precompile activates in the specified range. - if utils.IsForkTransition(upgrade.Timestamp(), from, to) { + if IsForkTransition(upgrade.Timestamp(), from, to) { configs = append(configs, upgrade.Config) } } diff --git a/params/state_upgrade.go b/params/state_upgrade.go index 3041d656d4..2b529a3f11 100644 --- a/params/state_upgrade.go +++ b/params/state_upgrade.go @@ -7,7 +7,6 @@ import ( "fmt" "reflect" - "github.com/ava-labs/subnet-evm/utils" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/common/math" @@ -62,7 +61,7 @@ func (c *ChainConfig) verifyStateUpgrades() error { func (c *ChainConfig) GetActivatingStateUpgrades(from *uint64, to uint64, upgrades []StateUpgrade) []StateUpgrade { activating := make([]StateUpgrade, 0) for _, upgrade := range upgrades { - if utils.IsForkTransition(upgrade.BlockTimestamp, from, to) { + if IsForkTransition(upgrade.BlockTimestamp, from, to) { activating = append(activating, upgrade) } } diff --git a/plugin/evm/vm.go b/plugin/evm/vm.go index 1547ae6156..49f3924ec1 100644 --- a/plugin/evm/vm.go +++ b/plugin/evm/vm.go @@ -375,7 +375,7 @@ func (vm *VM) Initialize( g.Config.Override(overrides) } - g.Config.SetEVMUpgrades(g.Config.NetworkUpgrades) + g.Config.SetEthUpgrades(g.Config.NetworkUpgrades) if err := g.Verify(); err != nil { return fmt.Errorf("failed to verify genesis: %w", err) diff --git a/plugin/evm/vm_test.go b/plugin/evm/vm_test.go index 468726ed85..15a359f42d 100644 --- a/plugin/evm/vm_test.go +++ b/plugin/evm/vm_test.go @@ -35,6 +35,7 @@ import ( commonEng "github.com/ava-labs/avalanchego/snow/engine/common" "github.com/ava-labs/avalanchego/snow/engine/enginetest" "github.com/ava-labs/avalanchego/snow/validators/validatorstest" + "github.com/ava-labs/avalanchego/upgrade" avalancheConstants "github.com/ava-labs/avalanchego/utils/constants" "github.com/ava-labs/avalanchego/utils/crypto/bls" "github.com/ava-labs/avalanchego/utils/formatting" @@ -2359,7 +2360,7 @@ func TestTxAllowListDisablePrecompile(t *testing.T) { if err := genesis.UnmarshalJSON([]byte(genesisJSONSubnetEVM)); err != nil { t.Fatal(err) } - enableAllowListTimestamp := params.DefaultGenesisTime // enable at default genesis time + enableAllowListTimestamp := upgrade.InitiallyActiveTime // enable at initially active time genesis.Config.GenesisPrecompiles = params.Precompiles{ txallowlist.ConfigKey: txallowlist.NewConfig(utils.TimeToNewUint64(enableAllowListTimestamp), testEthAddrs[0:1], nil, nil), } diff --git a/plugin/evm/vm_upgrade_bytes_test.go b/plugin/evm/vm_upgrade_bytes_test.go index 98e7ec6dcc..1960077647 100644 --- a/plugin/evm/vm_upgrade_bytes_test.go +++ b/plugin/evm/vm_upgrade_bytes_test.go @@ -38,7 +38,7 @@ var ( func TestVMUpgradeBytesPrecompile(t *testing.T) { // Make a TxAllowListConfig upgrade at genesis and convert it to JSON to apply as upgradeBytes. - enableAllowListTimestamp := params.DefaultGenesisTime // enable at default genesis time + enableAllowListTimestamp := upgrade.InitiallyActiveTime // enable at initial time upgradeConfig := ¶ms.UpgradeConfig{ PrecompileUpgrades: []params.PrecompileUpgrade{ { @@ -213,7 +213,7 @@ func TestNetworkUpgradesOverriden(t *testing.T) { require.False(t, vm.chainConfig.IsSubnetEVM(0)) require.True(t, vm.chainConfig.IsSubnetEVM(2)) require.False(t, vm.chainConfig.IsDurango(0)) - require.False(t, vm.chainConfig.IsDurango(uint64(params.DefaultGenesisTime.Unix()))) + require.False(t, vm.chainConfig.IsDurango(uint64(upgrade.InitiallyActiveTime.Unix()))) require.True(t, vm.chainConfig.IsDurango(1607144402)) } @@ -257,7 +257,7 @@ func TestVMStateUpgrade(t *testing.T) { Code: upgradedCode, } - upgradeTimestamp := params.DefaultGenesisTime.Add(10 * time.Hour) + upgradeTimestamp := upgrade.InitiallyActiveTime.Add(10 * time.Hour) upgradeBytesJSON := fmt.Sprintf( `{ "stateUpgrades": [ diff --git a/plugin/evm/vm_warp_test.go b/plugin/evm/vm_warp_test.go index d5c46e540c..2b4109bae2 100644 --- a/plugin/evm/vm_warp_test.go +++ b/plugin/evm/vm_warp_test.go @@ -16,6 +16,7 @@ import ( "github.com/ava-labs/avalanchego/snow/engine/snowman/block" "github.com/ava-labs/avalanchego/snow/validators" "github.com/ava-labs/avalanchego/snow/validators/validatorstest" + "github.com/ava-labs/avalanchego/upgrade" avagoUtils "github.com/ava-labs/avalanchego/utils" "github.com/ava-labs/avalanchego/utils/crypto/bls" "github.com/ava-labs/avalanchego/utils/set" @@ -49,7 +50,7 @@ func TestSendWarpMessage(t *testing.T) { genesis := &core.Genesis{} require.NoError(genesis.UnmarshalJSON([]byte(genesisJSONDurango))) genesis.Config.GenesisPrecompiles = params.Precompiles{ - warp.ConfigKey: warp.NewDefaultConfig(utils.TimeToNewUint64(params.DefaultGenesisTime)), + warp.ConfigKey: warp.NewDefaultConfig(utils.TimeToNewUint64(upgrade.InitiallyActiveTime)), } genesisJSON, err := genesis.MarshalJSON() require.NoError(err) @@ -247,7 +248,7 @@ func testWarpVMTransaction(t *testing.T, unsignedMessage *avalancheWarp.Unsigned genesis := &core.Genesis{} require.NoError(genesis.UnmarshalJSON([]byte(genesisJSONDurango))) genesis.Config.GenesisPrecompiles = params.Precompiles{ - warp.ConfigKey: warp.NewDefaultConfig(utils.TimeToNewUint64(params.DefaultGenesisTime)), + warp.ConfigKey: warp.NewDefaultConfig(utils.TimeToNewUint64(upgrade.InitiallyActiveTime)), } genesisJSON, err := genesis.MarshalJSON() require.NoError(err) @@ -403,7 +404,7 @@ func TestReceiveWarpMessage(t *testing.T) { genesis := &core.Genesis{} require.NoError(genesis.UnmarshalJSON([]byte(genesisJSONDurango))) genesis.Config.GenesisPrecompiles = params.Precompiles{ - warp.ConfigKey: warp.NewDefaultConfig(utils.TimeToNewUint64(params.DefaultGenesisTime)), + warp.ConfigKey: warp.NewDefaultConfig(utils.TimeToNewUint64(upgrade.InitiallyActiveTime)), } genesisJSON, err := genesis.MarshalJSON() require.NoError(err) diff --git a/utils/fork.go b/utils/fork.go deleted file mode 100644 index 0a2c150f2a..0000000000 --- a/utils/fork.go +++ /dev/null @@ -1,72 +0,0 @@ -// (c) 2019-2020, Ava Labs, Inc. All rights reserved. -// See the file LICENSE for licensing terms. - -package utils - -import ( - "math/big" - "time" -) - -func NewUint64(val uint64) *uint64 { return &val } - -func TimeToNewUint64(time time.Time) *uint64 { - unix := uint64(time.Unix()) - return NewUint64(unix) -} - -func Uint64ToTime(val *uint64) time.Time { - timestamp := int64(*val) - return time.Unix(timestamp, 0) -} - -// IsBlockForked returns whether a fork scheduled at block s is active at the given head block. -// Note: [s] and [head] can be either a block number or a block timestamp. -func IsBlockForked(s, head *big.Int) bool { - if s == nil || head == nil { - return false - } - return s.Cmp(head) <= 0 -} - -// IsTimestampForked returns whether a fork scheduled at timestamp s is active -// at the given head timestamp. Whilst this method is the same as isBlockForked, -// they are explicitly separate for clearer reading. -func IsTimestampForked(s *uint64, head uint64) bool { - if s == nil { - return false - } - return *s <= head -} - -// IsForkTransition returns true if [fork] activates during the transition from -// [parent] to [current]. -// Taking [parent] as a pointer allows for us to pass nil when checking forks -// that activate during genesis. -// Note: this works for both block number and timestamp activated forks. -func IsForkTransition(fork *uint64, parent *uint64, current uint64) bool { - var parentForked bool - if parent != nil { - parentForked = IsTimestampForked(fork, *parent) - } - currentForked := IsTimestampForked(fork, current) - return !parentForked && currentForked -} - -// BigNumEqual returns true if x and y are equivalent ie. both nil or both -// contain the same value. -func BigNumEqual(x, y *big.Int) bool { - if x == nil || y == nil { - return x == y - } - return x.Cmp(y) == 0 -} - -// Uint64PtrEqual returns true if x and y pointers are equivalent ie. both nil or both -// contain the same value. -func Uint64PtrEqual(x, y *uint64) bool { - if x == nil || y == nil { - return x == y - } - return *x == *y -} diff --git a/utils/numbers.go b/utils/numbers.go new file mode 100644 index 0000000000..d665b2f8e8 --- /dev/null +++ b/utils/numbers.go @@ -0,0 +1,39 @@ +// (c) 2019-2020, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package utils + +import ( + "math/big" + "time" +) + +func NewUint64(val uint64) *uint64 { return &val } + +func TimeToNewUint64(time time.Time) *uint64 { + unix := uint64(time.Unix()) + return NewUint64(unix) +} + +func Uint64ToTime(val *uint64) time.Time { + timestamp := int64(*val) + return time.Unix(timestamp, 0) +} + +// BigNumEqual returns true if x and y are equivalent ie. both nil or both +// contain the same value. +func BigNumEqual(x, y *big.Int) bool { + if x == nil || y == nil { + return x == y + } + return x.Cmp(y) == 0 +} + +// Uint64PtrEqual returns true if x and y pointers are equivalent ie. both nil or both +// contain the same value. +func Uint64PtrEqual(x, y *uint64) bool { + if x == nil || y == nil { + return x == y + } + return *x == *y +}