diff --git a/core/blockchain_test.go b/core/blockchain_test.go index d2fa3b62b3..95e703c5ad 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -16,6 +16,7 @@ import ( "github.com/ava-labs/coreth/core/state/pruner" "github.com/ava-labs/coreth/core/types" "github.com/ava-labs/coreth/params" + "github.com/ava-labs/coreth/params/extras" "github.com/ava-labs/libevm/common" "github.com/ava-labs/libevm/core/vm" "github.com/ava-labs/libevm/crypto" @@ -425,7 +426,7 @@ func TestUngracefulAsyncShutdown(t *testing.T) { gspec := &Genesis{ Config: params.WithExtra( ¶ms.ChainConfig{HomesteadBlock: new(big.Int)}, - ¶ms.ChainConfigExtra{}, + &extras.ChainConfig{}, ), Alloc: types.GenesisAlloc{addr1: {Balance: genesisBalance}}, } diff --git a/core/genesis_extra_test.go b/core/genesis_extra_test.go index 7889d6668d..6701fefe0e 100644 --- a/core/genesis_extra_test.go +++ b/core/genesis_extra_test.go @@ -34,6 +34,7 @@ import ( "github.com/ava-labs/coreth/core/rawdb" "github.com/ava-labs/coreth/core/types" "github.com/ava-labs/coreth/params" + "github.com/ava-labs/coreth/params/extras" "github.com/ava-labs/coreth/utils" "github.com/ava-labs/libevm/common" "github.com/ava-labs/libevm/triedb" @@ -57,8 +58,8 @@ func TestGenesisEthUpgrades(t *testing.T) { IstanbulBlock: big.NewInt(0), MuirGlacierBlock: big.NewInt(0), }, - ¶ms.ChainConfigExtra{ - NetworkUpgrades: params.NetworkUpgrades{ + &extras.ChainConfig{ + NetworkUpgrades: extras.NetworkUpgrades{ ApricotPhase1BlockTimestamp: utils.NewUint64(0), ApricotPhase2BlockTimestamp: utils.NewUint64(0), }, diff --git a/core/genesis_test.go b/core/genesis_test.go index 94d3435f7d..9fba3f209e 100644 --- a/core/genesis_test.go +++ b/core/genesis_test.go @@ -37,6 +37,7 @@ import ( "github.com/ava-labs/coreth/core/rawdb" "github.com/ava-labs/coreth/core/types" "github.com/ava-labs/coreth/params" + "github.com/ava-labs/coreth/params/extras" "github.com/ava-labs/coreth/precompile/contracts/warp" "github.com/ava-labs/coreth/triedb/pathdb" "github.com/ava-labs/coreth/utils" @@ -257,7 +258,7 @@ func TestGenesisWriteUpgradesRegression(t *testing.T) { _, _, err := SetupGenesisBlock(db, trieDB, genesis, genesisBlock.Hash(), false) require.NoError(err) - params.GetExtra(genesis.Config).UpgradeConfig.PrecompileUpgrades = []params.PrecompileUpgrade{ + params.GetExtra(genesis.Config).UpgradeConfig.PrecompileUpgrades = []extras.PrecompileUpgrade{ { Config: warp.NewConfig(utils.NewUint64(51), 0, false), }, diff --git a/core/state_processor_test.go b/core/state_processor_test.go index cc05576f25..64179f4290 100644 --- a/core/state_processor_test.go +++ b/core/state_processor_test.go @@ -38,6 +38,7 @@ import ( "github.com/ava-labs/coreth/core/rawdb" "github.com/ava-labs/coreth/core/types" "github.com/ava-labs/coreth/params" + "github.com/ava-labs/coreth/params/extras" "github.com/ava-labs/coreth/utils" "github.com/ava-labs/libevm/common" "github.com/ava-labs/libevm/core/vm" @@ -270,8 +271,8 @@ func TestStateProcessorErrors(t *testing.T) { IstanbulBlock: big.NewInt(0), MuirGlacierBlock: big.NewInt(0), }, - ¶ms.ChainConfigExtra{ - NetworkUpgrades: params.NetworkUpgrades{ + &extras.ChainConfig{ + NetworkUpgrades: extras.NetworkUpgrades{ ApricotPhase1BlockTimestamp: utils.NewUint64(0), ApricotPhase2BlockTimestamp: utils.NewUint64(0), }, diff --git a/core/vm/runtime/runtime.go b/core/vm/runtime/runtime.go index d190e85b1c..c66342e918 100644 --- a/core/vm/runtime/runtime.go +++ b/core/vm/runtime/runtime.go @@ -34,6 +34,7 @@ import ( "github.com/ava-labs/coreth/core/state" "github.com/ava-labs/coreth/core/types" "github.com/ava-labs/coreth/params" + "github.com/ava-labs/coreth/params/extras" "github.com/ava-labs/libevm/common" "github.com/ava-labs/libevm/core/vm" "github.com/ava-labs/libevm/crypto" @@ -84,8 +85,8 @@ func setDefaults(cfg *Config) { LondonBlock: new(big.Int), BerlinBlock: new(big.Int), }, - ¶ms.ChainConfigExtra{ - NetworkUpgrades: params.NetworkUpgrades{ + &extras.ChainConfig{ + NetworkUpgrades: extras.NetworkUpgrades{ ApricotPhase1BlockTimestamp: new(uint64), ApricotPhase2BlockTimestamp: new(uint64), ApricotPhase3BlockTimestamp: new(uint64), diff --git a/params/config.go b/params/config.go index c064978cd6..e44e41e287 100644 --- a/params/config.go +++ b/params/config.go @@ -31,6 +31,7 @@ import ( "github.com/ava-labs/avalanchego/upgrade" "github.com/ava-labs/avalanchego/utils/constants" + "github.com/ava-labs/coreth/params/extras" "github.com/ava-labs/coreth/utils" ethparams "github.com/ava-labs/libevm/params" ) @@ -68,9 +69,9 @@ var ( ShanghaiTime: utils.TimeToNewUint64(upgrade.GetConfig(constants.UnitTestID).DurangoTime), CancunTime: utils.TimeToNewUint64(upgrade.GetConfig(constants.UnitTestID).EtnaTime), }, - &ChainConfigExtra{ - AvalancheContext: AvalancheContext{utils.TestSnowContext()}, - NetworkUpgrades: NetworkUpgrades{ + &extras.ChainConfig{ + AvalancheContext: extras.AvalancheContext{SnowCtx: utils.TestSnowContext()}, + NetworkUpgrades: extras.NetworkUpgrades{ ApricotPhase1BlockTimestamp: utils.NewUint64(0), ApricotPhase2BlockTimestamp: utils.NewUint64(0), ApricotPhase3BlockTimestamp: utils.NewUint64(0), @@ -101,9 +102,9 @@ var ( IstanbulBlock: big.NewInt(0), MuirGlacierBlock: big.NewInt(0), }, - &ChainConfigExtra{ - AvalancheContext: AvalancheContext{utils.TestSnowContext()}, - NetworkUpgrades: NetworkUpgrades{ + &extras.ChainConfig{ + AvalancheContext: extras.AvalancheContext{SnowCtx: utils.TestSnowContext()}, + NetworkUpgrades: extras.NetworkUpgrades{ ApricotPhase1BlockTimestamp: nil, ApricotPhase2BlockTimestamp: nil, ApricotPhase3BlockTimestamp: nil, @@ -134,9 +135,9 @@ var ( IstanbulBlock: big.NewInt(0), MuirGlacierBlock: big.NewInt(0), }, - &ChainConfigExtra{ - AvalancheContext: AvalancheContext{utils.TestSnowContext()}, - NetworkUpgrades: NetworkUpgrades{ + &extras.ChainConfig{ + AvalancheContext: extras.AvalancheContext{SnowCtx: utils.TestSnowContext()}, + NetworkUpgrades: extras.NetworkUpgrades{ ApricotPhase1BlockTimestamp: utils.NewUint64(0), ApricotPhase2BlockTimestamp: nil, ApricotPhase3BlockTimestamp: nil, @@ -168,9 +169,9 @@ var ( MuirGlacierBlock: big.NewInt(0), BerlinBlock: big.NewInt(0), }, - &ChainConfigExtra{ - AvalancheContext: AvalancheContext{utils.TestSnowContext()}, - NetworkUpgrades: NetworkUpgrades{ + &extras.ChainConfig{ + AvalancheContext: extras.AvalancheContext{SnowCtx: utils.TestSnowContext()}, + NetworkUpgrades: extras.NetworkUpgrades{ ApricotPhase1BlockTimestamp: utils.NewUint64(0), ApricotPhase2BlockTimestamp: utils.NewUint64(0), ApricotPhase3BlockTimestamp: nil, @@ -203,9 +204,9 @@ var ( BerlinBlock: big.NewInt(0), LondonBlock: big.NewInt(0), }, - &ChainConfigExtra{ - AvalancheContext: AvalancheContext{utils.TestSnowContext()}, - NetworkUpgrades: NetworkUpgrades{ + &extras.ChainConfig{ + AvalancheContext: extras.AvalancheContext{SnowCtx: utils.TestSnowContext()}, + NetworkUpgrades: extras.NetworkUpgrades{ ApricotPhase1BlockTimestamp: utils.NewUint64(0), ApricotPhase2BlockTimestamp: utils.NewUint64(0), ApricotPhase3BlockTimestamp: utils.NewUint64(0), @@ -238,9 +239,9 @@ var ( BerlinBlock: big.NewInt(0), LondonBlock: big.NewInt(0), }, - &ChainConfigExtra{ - AvalancheContext: AvalancheContext{utils.TestSnowContext()}, - NetworkUpgrades: NetworkUpgrades{ + &extras.ChainConfig{ + AvalancheContext: extras.AvalancheContext{SnowCtx: utils.TestSnowContext()}, + NetworkUpgrades: extras.NetworkUpgrades{ ApricotPhase1BlockTimestamp: utils.NewUint64(0), ApricotPhase2BlockTimestamp: utils.NewUint64(0), ApricotPhase3BlockTimestamp: utils.NewUint64(0), @@ -273,9 +274,9 @@ var ( BerlinBlock: big.NewInt(0), LondonBlock: big.NewInt(0), }, - &ChainConfigExtra{ - AvalancheContext: AvalancheContext{utils.TestSnowContext()}, - NetworkUpgrades: NetworkUpgrades{ + &extras.ChainConfig{ + AvalancheContext: extras.AvalancheContext{SnowCtx: utils.TestSnowContext()}, + NetworkUpgrades: extras.NetworkUpgrades{ ApricotPhase1BlockTimestamp: utils.NewUint64(0), ApricotPhase2BlockTimestamp: utils.NewUint64(0), ApricotPhase3BlockTimestamp: utils.NewUint64(0), @@ -308,9 +309,9 @@ var ( BerlinBlock: big.NewInt(0), LondonBlock: big.NewInt(0), }, - &ChainConfigExtra{ - AvalancheContext: AvalancheContext{utils.TestSnowContext()}, - NetworkUpgrades: NetworkUpgrades{ + &extras.ChainConfig{ + AvalancheContext: extras.AvalancheContext{SnowCtx: utils.TestSnowContext()}, + NetworkUpgrades: extras.NetworkUpgrades{ ApricotPhase1BlockTimestamp: utils.NewUint64(0), ApricotPhase2BlockTimestamp: utils.NewUint64(0), ApricotPhase3BlockTimestamp: utils.NewUint64(0), @@ -343,9 +344,9 @@ var ( BerlinBlock: big.NewInt(0), LondonBlock: big.NewInt(0), }, - &ChainConfigExtra{ - AvalancheContext: AvalancheContext{utils.TestSnowContext()}, - NetworkUpgrades: NetworkUpgrades{ + &extras.ChainConfig{ + AvalancheContext: extras.AvalancheContext{SnowCtx: utils.TestSnowContext()}, + NetworkUpgrades: extras.NetworkUpgrades{ ApricotPhase1BlockTimestamp: utils.NewUint64(0), ApricotPhase2BlockTimestamp: utils.NewUint64(0), ApricotPhase3BlockTimestamp: utils.NewUint64(0), @@ -378,9 +379,9 @@ var ( BerlinBlock: big.NewInt(0), LondonBlock: big.NewInt(0), }, - &ChainConfigExtra{ - AvalancheContext: AvalancheContext{utils.TestSnowContext()}, - NetworkUpgrades: NetworkUpgrades{ + &extras.ChainConfig{ + AvalancheContext: extras.AvalancheContext{SnowCtx: utils.TestSnowContext()}, + NetworkUpgrades: extras.NetworkUpgrades{ ApricotPhase1BlockTimestamp: utils.NewUint64(0), ApricotPhase2BlockTimestamp: utils.NewUint64(0), ApricotPhase3BlockTimestamp: utils.NewUint64(0), @@ -413,9 +414,9 @@ var ( BerlinBlock: big.NewInt(0), LondonBlock: big.NewInt(0), }, - &ChainConfigExtra{ - AvalancheContext: AvalancheContext{utils.TestSnowContext()}, - NetworkUpgrades: NetworkUpgrades{ + &extras.ChainConfig{ + AvalancheContext: extras.AvalancheContext{SnowCtx: utils.TestSnowContext()}, + NetworkUpgrades: extras.NetworkUpgrades{ ApricotPhase1BlockTimestamp: utils.NewUint64(0), ApricotPhase2BlockTimestamp: utils.NewUint64(0), ApricotPhase3BlockTimestamp: utils.NewUint64(0), @@ -448,9 +449,9 @@ var ( BerlinBlock: big.NewInt(0), LondonBlock: big.NewInt(0), }, - &ChainConfigExtra{ - AvalancheContext: AvalancheContext{utils.TestSnowContext()}, - NetworkUpgrades: NetworkUpgrades{ + &extras.ChainConfig{ + AvalancheContext: extras.AvalancheContext{SnowCtx: utils.TestSnowContext()}, + NetworkUpgrades: extras.NetworkUpgrades{ ApricotPhase1BlockTimestamp: utils.NewUint64(0), ApricotPhase2BlockTimestamp: utils.NewUint64(0), ApricotPhase3BlockTimestamp: utils.NewUint64(0), @@ -484,9 +485,9 @@ var ( LondonBlock: big.NewInt(0), ShanghaiTime: utils.NewUint64(0), }, - &ChainConfigExtra{ - AvalancheContext: AvalancheContext{utils.TestSnowContext()}, - NetworkUpgrades: NetworkUpgrades{ + &extras.ChainConfig{ + AvalancheContext: extras.AvalancheContext{SnowCtx: utils.TestSnowContext()}, + NetworkUpgrades: extras.NetworkUpgrades{ ApricotPhase1BlockTimestamp: utils.NewUint64(0), ApricotPhase2BlockTimestamp: utils.NewUint64(0), ApricotPhase3BlockTimestamp: utils.NewUint64(0), @@ -521,9 +522,9 @@ var ( ShanghaiTime: utils.NewUint64(0), CancunTime: utils.NewUint64(0), }, - &ChainConfigExtra{ - AvalancheContext: AvalancheContext{utils.TestSnowContext()}, - NetworkUpgrades: NetworkUpgrades{ + &extras.ChainConfig{ + AvalancheContext: extras.AvalancheContext{SnowCtx: utils.TestSnowContext()}, + NetworkUpgrades: extras.NetworkUpgrades{ ApricotPhase1BlockTimestamp: utils.NewUint64(0), ApricotPhase2BlockTimestamp: utils.NewUint64(0), ApricotPhase3BlockTimestamp: utils.NewUint64(0), diff --git a/params/config_extra.go b/params/config_extra.go index be1afcc316..a9e5b0bdd9 100644 --- a/params/config_extra.go +++ b/params/config_extra.go @@ -6,14 +6,11 @@ package params import ( "encoding/json" "errors" - "fmt" "math/big" - "github.com/ava-labs/avalanchego/snow" "github.com/ava-labs/avalanchego/upgrade" + "github.com/ava-labs/coreth/params/extras" "github.com/ava-labs/coreth/utils" - "github.com/ava-labs/libevm/common" - ethparams "github.com/ava-labs/libevm/params" ) const ( @@ -24,18 +21,7 @@ const ( IsMergeTODO = true ) -// UpgradeConfig includes the following configs that may be specified in upgradeBytes: -// - Timestamps that enable avalanche network upgrades, -// - Enabling or disabling precompiles as network upgrades. -type UpgradeConfig struct { - // Config for enabling and disabling precompiles as network upgrades. - PrecompileUpgrades []PrecompileUpgrade `json:"precompileUpgrades,omitempty"` -} - -// AvalancheContext provides Avalanche specific context directly into the EVM. -type AvalancheContext struct { - SnowCtx *snow.Context -} +type ConfigCompatError = extras.ConfigCompatError // SetEthUpgrades enables Etheruem network upgrades using the same time as // the Avalanche network upgrade that enables them. @@ -72,11 +58,11 @@ func SetEthUpgrades(c *ChainConfig) { } } -func GetExtra(c *ChainConfig) *ChainConfigExtra { - ex := extras.FromChainConfig(c) +func GetExtra(c *ChainConfig) *extras.ChainConfig { + ex := payloads.FromChainConfig(c) if ex == nil { - ex = &ChainConfigExtra{} - extras.SetOnChainConfig(c, ex) + ex = &extras.ChainConfig{} + payloads.SetOnChainConfig(c, ex) } return ex } @@ -88,208 +74,14 @@ func Copy(c *ChainConfig) ChainConfig { } // WithExtra sets the extra payload on `c` and returns the modified argument. -func WithExtra(c *ChainConfig, extra *ChainConfigExtra) *ChainConfig { - extras.SetOnChainConfig(c, extra) +func WithExtra(c *ChainConfig, extra *extras.ChainConfig) *ChainConfig { + payloads.SetOnChainConfig(c, extra) return c } -type ChainConfigExtra struct { - NetworkUpgrades // Config for timestamps that enable network upgrades. Skip encoding/decoding directly into ChainConfig. - - AvalancheContext `json:"-"` // Avalanche specific context set during VM initialization. Not serialized. - - UpgradeConfig `json:"-"` // Config specified in upgradeBytes (avalanche network upgrades or enable/disabling precompiles). Skip encoding/decoding directly into ChainConfig. -} - -func (c *ChainConfigExtra) Description() string { - if c == nil { - return "" - } - var banner string - - banner += "Avalanche Upgrades (timestamp based):\n" - banner += c.NetworkUpgrades.Description() - 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" - return banner -} - -type fork struct { - name string - block *big.Int // some go-ethereum forks use block numbers - timestamp *uint64 // Avalanche forks use timestamps - optional bool // if true, the fork may be nil and next fork is still allowed -} - -func (c *ChainConfigExtra) CheckConfigForkOrder() error { - if c == nil { - return nil - } - // Note: In Avalanche, 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.forkOrder(), 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 lastFork.name != "" { - switch { - // Non-optional forks must all be present in the chain config up to the last defined fork - case lastFork.block == nil && lastFork.timestamp == nil && (cur.block != nil || cur.timestamp != nil): - if cur.block != nil { - return fmt.Errorf("unsupported fork ordering: %v not enabled, but %v enabled at block %v", - lastFork.name, cur.name, cur.block) - } else { - return fmt.Errorf("unsupported fork ordering: %v not enabled, but %v enabled at timestamp %v", - lastFork.name, cur.name, cur.timestamp) - } - - // Fork (whether defined by block or timestamp) must follow the fork definition sequence - case (lastFork.block != nil && cur.block != nil) || (lastFork.timestamp != nil && cur.timestamp != nil): - if lastFork.block != nil && lastFork.block.Cmp(cur.block) > 0 { - return fmt.Errorf("unsupported fork ordering: %v enabled at block %v, but %v enabled at block %v", - lastFork.name, lastFork.block, cur.name, cur.block) - } else if lastFork.timestamp != nil && *lastFork.timestamp > *cur.timestamp { - return fmt.Errorf("unsupported fork ordering: %v enabled at timestamp %v, but %v enabled at timestamp %v", - lastFork.name, lastFork.timestamp, cur.name, cur.timestamp) - } - - // Timestamp based forks can follow block based ones, but not the other way around - if lastFork.timestamp != nil && cur.block != nil { - return fmt.Errorf("unsupported fork ordering: %v used timestamp ordering, but %v reverted to block ordering", - lastFork.name, cur.name) - } - } - } - // If it was optional and not set, then ignore it - if !cur.optional || (cur.block != nil || cur.timestamp != nil) { - lastFork = cur - } - } - return nil -} - -func (c *ChainConfigExtra) CheckConfigCompatible(newcfg_ *ChainConfig, headNumber *big.Int, headTimestamp uint64) *ConfigCompatError { - if c == nil { - return nil - } - newcfg := GetExtra(newcfg_) - - // Check avalanche network upgrades - 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. - // XXX: This is missing in master? - // if err := c.checkPrecompilesCompatible(newcfg.PrecompileUpgrades, headTimestamp); err != nil { - // return err - // } - - return nil -} - -// 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 (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 { - 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 = ethparams.ConfigCompatError - -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 -} - -// 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 *ChainConfigExtra) UnmarshalJSON(data []byte) error { - // Alias ChainConfigExtra to avoid recursion - type _ChainConfigExtra ChainConfigExtra - tmp := _ChainConfigExtra{} - if err := json.Unmarshal(data, &tmp); err != nil { - return err - } - - // At this point we have populated all fields except PrecompileUpgrade - *c = ChainConfigExtra(tmp) - - return nil -} - -// MarshalJSON returns the JSON encoding of c. -// This is a custom marshaler to handle the Precompiles field. -func (c *ChainConfigExtra) MarshalJSON() ([]byte, error) { - // Alias ChainConfigExtra to avoid recursion - type _ChainConfigExtra ChainConfigExtra - return json.Marshal(_ChainConfigExtra(*c)) -} - type ChainConfigWithUpgradesJSON struct { ChainConfig - UpgradeConfig UpgradeConfig `json:"upgrades,omitempty"` + UpgradeConfig extras.UpgradeConfig `json:"upgrades,omitempty"` } // MarshalJSON implements json.Marshaler. This is a workaround for the fact that @@ -308,7 +100,7 @@ func (cu ChainConfigWithUpgradesJSON) MarshalJSON() ([]byte, error) { } type upgrades struct { - UpgradeConfig UpgradeConfig `json:"upgrades"` + UpgradeConfig extras.UpgradeConfig `json:"upgrades"` } upgradeJSON, err := json.Marshal(upgrades{cu.UpgradeConfig}) @@ -334,7 +126,7 @@ func (cu *ChainConfigWithUpgradesJSON) UnmarshalJSON(input []byte) error { } type upgrades struct { - UpgradeConfig UpgradeConfig `json:"upgrades"` + UpgradeConfig extras.UpgradeConfig `json:"upgrades"` } var u upgrades @@ -346,22 +138,6 @@ func (cu *ChainConfigWithUpgradesJSON) UnmarshalJSON(input []byte) error { return nil } -// Verify verifies chain config and returns error -func (c *ChainConfigExtra) Verify() error { - // 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) - } - - return nil -} - -// IsPrecompileEnabled returns whether precompile with [address] is enabled at [timestamp]. -func (c *ChainConfigExtra) IsPrecompileEnabled(address common.Address, timestamp uint64) bool { - config := c.getActivePrecompileConfig(address, timestamp) - return config != nil && !config.IsDisabled() -} - // 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. @@ -388,29 +164,8 @@ func GetChainConfig(agoUpgrade upgrade.Config, chainID *big.Int) *ChainConfig { IstanbulBlock: big.NewInt(0), MuirGlacierBlock: big.NewInt(0), }, - &ChainConfigExtra{ - NetworkUpgrades: getNetworkUpgrades(agoUpgrade), + &extras.ChainConfig{ + NetworkUpgrades: extras.GetNetworkUpgrades(agoUpgrade), }, ) } - -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/params/config_libevm.go b/params/config_libevm.go index c5db4f9db9..6ab46dbe7e 100644 --- a/params/config_libevm.go +++ b/params/config_libevm.go @@ -6,6 +6,7 @@ package params import ( "math/big" + "github.com/ava-labs/coreth/params/extras" "github.com/ava-labs/coreth/precompile/modules" "github.com/ava-labs/coreth/precompile/precompileconfig" "github.com/ava-labs/libevm/common" @@ -15,19 +16,19 @@ import ( // libevmInit would ideally be a regular init() function, but it MUST be run // before any calls to [ChainConfig.Rules]. See `config.go` for its call site. func libevmInit() any { - extras = ethparams.RegisterExtras(ethparams.Extras[*ChainConfigExtra, RulesExtra]{ + payloads = ethparams.RegisterExtras(ethparams.Extras[*extras.ChainConfig, RulesExtra]{ ReuseJSONRoot: true, // Reuse the root JSON input when unmarshalling the extra payload. NewRules: constructRulesExtra, }) return nil } -var extras ethparams.ExtraPayloads[*ChainConfigExtra, RulesExtra] +var payloads ethparams.ExtraPayloads[*extras.ChainConfig, RulesExtra] // constructRulesExtra acts as an adjunct to the [params.ChainConfig.Rules] // method. Its primary purpose is to construct the extra payload for the // [params.Rules] but it MAY also modify the [params.Rules]. -func constructRulesExtra(c *ethparams.ChainConfig, r *ethparams.Rules, cEx *ChainConfigExtra, blockNum *big.Int, isMerge bool, timestamp uint64) RulesExtra { +func constructRulesExtra(c *ethparams.ChainConfig, r *ethparams.Rules, cEx *extras.ChainConfig, blockNum *big.Int, isMerge bool, timestamp uint64) RulesExtra { var rules RulesExtra if cEx == nil { return rules @@ -39,7 +40,7 @@ func constructRulesExtra(c *ethparams.ChainConfig, r *ethparams.Rules, cEx *Chai rules.Predicaters = make(map[common.Address]precompileconfig.Predicater) rules.AccepterPrecompiles = make(map[common.Address]precompileconfig.Accepter) for _, module := range modules.RegisteredModules() { - if config := cEx.getActivePrecompileConfig(module.Address, timestamp); config != nil && !config.IsDisabled() { + if config := cEx.GetActivePrecompileConfig(module.Address, timestamp); config != nil && !config.IsDisabled() { rules.Precompiles[module.Address] = config if predicater, ok := config.(precompileconfig.Predicater); ok { rules.Predicaters[module.Address] = predicater diff --git a/params/config_test.go b/params/config_test.go index e5c7b97bdf..3ad2097a07 100644 --- a/params/config_test.go +++ b/params/config_test.go @@ -33,6 +33,7 @@ import ( "testing" "time" + "github.com/ava-labs/coreth/params/extras" "github.com/ava-labs/coreth/utils" ) @@ -146,8 +147,8 @@ func TestCheckCompatible(t *testing.T) { func TestConfigRules(t *testing.T) { c := WithExtra( &ChainConfig{}, - &ChainConfigExtra{ - NetworkUpgrades: NetworkUpgrades{ + &extras.ChainConfig{ + NetworkUpgrades: extras.NetworkUpgrades{ CortinaBlockTimestamp: utils.NewUint64(500), }, }, diff --git a/params/extras/config.go b/params/extras/config.go new file mode 100644 index 0000000000..14b17bc56e --- /dev/null +++ b/params/extras/config.go @@ -0,0 +1,268 @@ +// (c) 2024 Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package extras + +import ( + "encoding/json" + "fmt" + "math/big" + + "github.com/ava-labs/avalanchego/snow" + "github.com/ava-labs/coreth/utils" + "github.com/ava-labs/libevm/common" + ethparams "github.com/ava-labs/libevm/params" +) + +// UpgradeConfig includes the following configs that may be specified in upgradeBytes: +// - Timestamps that enable avalanche network upgrades, +// - Enabling or disabling precompiles as network upgrades. +type UpgradeConfig struct { + // Config for enabling and disabling precompiles as network upgrades. + PrecompileUpgrades []PrecompileUpgrade `json:"precompileUpgrades,omitempty"` +} + +// AvalancheContext provides Avalanche specific context directly into the EVM. +type AvalancheContext struct { + SnowCtx *snow.Context +} + +type ChainConfig struct { + NetworkUpgrades // Config for timestamps that enable network upgrades. + + AvalancheContext `json:"-"` // Avalanche specific context set during VM initialization. Not serialized. + + UpgradeConfig `json:"-"` // Config specified in upgradeBytes (avalanche network upgrades or enable/disabling precompiles). Not serialized. +} + +func (c *ChainConfig) CheckConfigCompatible(newcfg_ *ethparams.ChainConfig, headNumber *big.Int, headTimestamp uint64) *ConfigCompatError { + if c == nil { + return nil + } + newcfg, ok := newcfg_.Hooks().(*ChainConfig) + if !ok { + // Proper registration of the extras on libevm side should prevent this from happening. + // Return an error to prevent the chain from starting, just in case. + return newTimestampCompatError( + fmt.Sprintf("ChainConfig.Hooks() is not of the expected type *extras.ChainConfig, got %T", newcfg_.Hooks()), + utils.NewUint64(0), + 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. + // XXX: This is missing in master? + // if err := c.checkPrecompilesCompatible(newcfg.PrecompileUpgrades, headTimestamp); err != nil { + // return err + // } + + return nil +} + +func (c *ChainConfig) Description() string { + if c == nil { + return "" + } + var banner string + + banner += "Avalanche Upgrades (timestamp based):\n" + banner += c.NetworkUpgrades.Description() + 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" + return banner +} + +// 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 (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 { + 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 = ethparams.ConfigCompatError + +// newTimestampCompatError is taken verbatim from upstream. +// TODO: export this function from upstream in libevm, so it can be used here. +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 +} + +// 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 ChainConfigExtra to avoid recursion + type _ChainConfigExtra ChainConfig + tmp := _ChainConfigExtra{} + if err := json.Unmarshal(data, &tmp); err != nil { + return err + } + + // At this point we have populated all fields except PrecompileUpgrade + *c = ChainConfig(tmp) + + return nil +} + +// MarshalJSON returns the JSON encoding of c. +// This is a custom marshaler to handle the Precompiles field. +func (c *ChainConfig) MarshalJSON() ([]byte, error) { + // Alias ChainConfigExtra to avoid recursion + type _ChainConfigExtra ChainConfig + return json.Marshal(_ChainConfigExtra(*c)) +} + +type fork struct { + name string + block *big.Int // some go-ethereum forks use block numbers + timestamp *uint64 // Avalanche forks use timestamps + optional bool // if true, the fork may be nil and next fork is still allowed +} + +func (c *ChainConfig) CheckConfigForkOrder() error { + if c == nil { + return nil + } + // Note: In Avalanche, upgrades must take place via block timestamps instead + // of block numbers since blocks are produced asynchronously. Therefore, we do + // not check block timestamp forks in the same way as block number forks since + // it would not be a meaningful comparison. Instead, we only check that the + // Avalanche upgrades are enabled in order. + // Note: we do not add the precompile configs here because they are optional + // and independent, i.e. the order in which they are enabled does not impact + // the correctness of the chain config. + return checkForks(c.forkOrder(), false) +} + +// 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 +// TODO: This code was adapted from CheckConfigForkOrder, consider refactoring to avoid duplication. +func checkForks(forks []fork, blockFork bool) error { + lastFork := fork{} + for _, cur := range forks { + if lastFork.name != "" { + switch { + // Non-optional forks must all be present in the chain config up to the last defined fork + case lastFork.block == nil && lastFork.timestamp == nil && (cur.block != nil || cur.timestamp != nil): + if cur.block != nil { + return fmt.Errorf("unsupported fork ordering: %v not enabled, but %v enabled at block %v", + lastFork.name, cur.name, cur.block) + } else { + return fmt.Errorf("unsupported fork ordering: %v not enabled, but %v enabled at timestamp %v", + lastFork.name, cur.name, cur.timestamp) + } + + // Fork (whether defined by block or timestamp) must follow the fork definition sequence + case (lastFork.block != nil && cur.block != nil) || (lastFork.timestamp != nil && cur.timestamp != nil): + if lastFork.block != nil && lastFork.block.Cmp(cur.block) > 0 { + return fmt.Errorf("unsupported fork ordering: %v enabled at block %v, but %v enabled at block %v", + lastFork.name, lastFork.block, cur.name, cur.block) + } else if lastFork.timestamp != nil && *lastFork.timestamp > *cur.timestamp { + return fmt.Errorf("unsupported fork ordering: %v enabled at timestamp %v, but %v enabled at timestamp %v", + lastFork.name, lastFork.timestamp, cur.name, cur.timestamp) + } + + // Timestamp based forks can follow block based ones, but not the other way around + if lastFork.timestamp != nil && cur.block != nil { + return fmt.Errorf("unsupported fork ordering: %v used timestamp ordering, but %v reverted to block ordering", + lastFork.name, cur.name) + } + } + } + // If it was optional and not set, then ignore it + if !cur.optional || (cur.block != nil || cur.timestamp != nil) { + lastFork = cur + } + } + return nil +} + +// Verify verifies chain config. +func (c *ChainConfig) Verify() error { + // 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) + } + + 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() +} + +// 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: [parent] and [current] can be either both timestamp values, or both +// block number values, since this function 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 +} + +func ptrToString(val *uint64) string { + if val == nil { + return "nil" + } + return fmt.Sprintf("%d", *val) +} diff --git a/params/config_extra_test.go b/params/extras/config_extra_test.go similarity index 99% rename from params/config_extra_test.go rename to params/extras/config_extra_test.go index 64438b7f07..a94264cf31 100644 --- a/params/config_extra_test.go +++ b/params/extras/config_extra_test.go @@ -1,7 +1,7 @@ // (c) 2024 Ava Labs, Inc. All rights reserved. // See the file LICENSE for licensing terms. -package params +package extras import ( "testing" diff --git a/params/network_upgrades.go b/params/extras/network_upgrades.go similarity index 99% rename from params/network_upgrades.go rename to params/extras/network_upgrades.go index 72e9b4e29b..6488469d23 100644 --- a/params/network_upgrades.go +++ b/params/extras/network_upgrades.go @@ -1,7 +1,7 @@ // (c) 2022, Ava Labs, Inc. All rights reserved. // See the file LICENSE for licensing terms. -package params +package extras import ( "fmt" @@ -194,7 +194,7 @@ func (n NetworkUpgrades) Description() string { return banner } -func getNetworkUpgrades(agoUpgrade upgrade.Config) NetworkUpgrades { +func GetNetworkUpgrades(agoUpgrade upgrade.Config) NetworkUpgrades { return NetworkUpgrades{ ApricotPhase1BlockTimestamp: utils.TimeToNewUint64(agoUpgrade.ApricotPhase1Time), ApricotPhase2BlockTimestamp: utils.TimeToNewUint64(agoUpgrade.ApricotPhase2Time), diff --git a/params/precompile_upgrade.go b/params/extras/precompile_upgrade.go similarity index 90% rename from params/precompile_upgrade.go rename to params/extras/precompile_upgrade.go index 7a7c3b07b5..6f1522673d 100644 --- a/params/precompile_upgrade.go +++ b/params/extras/precompile_upgrade.go @@ -1,7 +1,7 @@ // (c) 2023 Ava Labs, Inc. All rights reserved. // See the file LICENSE for licensing terms. -package params +package extras import ( "encoding/json" @@ -67,7 +67,7 @@ func (u *PrecompileUpgrade) MarshalJSON() ([]byte, error) { // - the specified blockTimestamps must be compatible with those // specified in the chainConfig by genesis. // - check a precompile is disabled before it is re-enabled -func (c *ChainConfigExtra) verifyPrecompileUpgrades() error { +func (c *ChainConfig) verifyPrecompileUpgrades() error { // Store this struct to keep track of the last upgrade for each precompile key. // Required for timestamp and disabled checks. type lastUpgradeData struct { @@ -131,9 +131,9 @@ func (c *ChainConfigExtra) verifyPrecompileUpgrades() error { return nil } -// getActivePrecompileConfig returns the most recent precompile config corresponding to [address]. +// GetActivePrecompileConfig returns the most recent precompile config corresponding to [address]. // If none have occurred, returns nil. -func (c *ChainConfigExtra) getActivePrecompileConfig(address common.Address, timestamp uint64) precompileconfig.Config { +func (c *ChainConfig) GetActivePrecompileConfig(address common.Address, timestamp uint64) precompileconfig.Config { configs := c.GetActivatingPrecompileConfigs(address, nil, timestamp, c.PrecompileUpgrades) if len(configs) == 0 { return nil @@ -143,7 +143,7 @@ func (c *ChainConfigExtra) getActivePrecompileConfig(address common.Address, tim // GetActivatingPrecompileConfigs returns all precompile upgrades configured to activate during the // state transition from a block with timestamp [from] to a block with timestamp [to]. -func (c *ChainConfigExtra) GetActivatingPrecompileConfigs(address common.Address, from *uint64, to uint64, upgrades []PrecompileUpgrade) []precompileconfig.Config { +func (c *ChainConfig) GetActivatingPrecompileConfigs(address common.Address, from *uint64, to uint64, upgrades []PrecompileUpgrade) []precompileconfig.Config { // Get key from address. module, ok := modules.GetPrecompileModuleByAddress(address) if !ok { @@ -172,7 +172,7 @@ func (c *ChainConfigExtra) GetActivatingPrecompileConfigs(address common.Address // new upgrade to be applied as long as it activates after the last accepted block. // //nolint:unused -func (c *ChainConfigExtra) checkPrecompilesCompatible(precompileUpgrades []PrecompileUpgrade, time uint64) *ConfigCompatError { +func (c *ChainConfig) checkPrecompilesCompatible(precompileUpgrades []PrecompileUpgrade, time uint64) *ConfigCompatError { for _, module := range modules.RegisteredModules() { if err := c.checkPrecompileCompatible(module.Address, precompileUpgrades, time); err != nil { return err @@ -188,7 +188,7 @@ func (c *ChainConfigExtra) checkPrecompilesCompatible(precompileUpgrades []Preco // Upgrades that have already gone into effect cannot be modified or absent from [precompileUpgrades]. // //nolint:unused -func (c *ChainConfigExtra) checkPrecompileCompatible(address common.Address, precompileUpgrades []PrecompileUpgrade, time uint64) *ConfigCompatError { +func (c *ChainConfig) checkPrecompileCompatible(address common.Address, precompileUpgrades []PrecompileUpgrade, time uint64) *ConfigCompatError { // All active upgrades (from nil to [lastTimestamp]) must match. activeUpgrades := c.GetActivatingPrecompileConfigs(address, nil, time, c.PrecompileUpgrades) newUpgrades := c.GetActivatingPrecompileConfigs(address, nil, time, precompileUpgrades) @@ -226,10 +226,10 @@ func (c *ChainConfigExtra) checkPrecompileCompatible(address common.Address, pre } // EnabledStatefulPrecompiles returns current stateful precompile configs that are enabled at [blockTimestamp]. -func (c *ChainConfigExtra) EnabledStatefulPrecompiles(blockTimestamp uint64) Precompiles { +func (c *ChainConfig) EnabledStatefulPrecompiles(blockTimestamp uint64) Precompiles { statefulPrecompileConfigs := make(Precompiles) for _, module := range modules.RegisteredModules() { - if config := c.getActivePrecompileConfig(module.Address, blockTimestamp); config != nil && !config.IsDisabled() { + if config := c.GetActivePrecompileConfig(module.Address, blockTimestamp); config != nil && !config.IsDisabled() { statefulPrecompileConfigs[module.ConfigKey] = config } } diff --git a/params/precompiles.go b/params/extras/precompiles.go similarity index 98% rename from params/precompiles.go rename to params/extras/precompiles.go index 9b47b219fd..10bbd1161a 100644 --- a/params/precompiles.go +++ b/params/extras/precompiles.go @@ -1,7 +1,7 @@ // (c) 2023 Ava Labs, Inc. All rights reserved. // See the file LICENSE for licensing terms. -package params +package extras import ( "encoding/json" diff --git a/params/rules_extra.go b/params/extras/rules.go similarity index 78% rename from params/rules_extra.go rename to params/extras/rules.go index b0e42a62a7..40b51a3ba2 100644 --- a/params/rules_extra.go +++ b/params/extras/rules.go @@ -1,18 +1,14 @@ // (c) 2024 Ava Labs, Inc. All rights reserved. // See the file LICENSE for licensing terms. -package params +package extras import ( "github.com/ava-labs/coreth/precompile/precompileconfig" "github.com/ava-labs/libevm/common" ) -func GetRulesExtra(r Rules) *RulesExtra { - return extras.PointerFromRules(&r) -} - -type RulesExtra struct { +type Rules struct { // Rules for Avalanche releases AvalancheRules @@ -29,17 +25,17 @@ type RulesExtra struct { AccepterPrecompiles map[common.Address]precompileconfig.Accepter } -func (r *RulesExtra) PredicatersExist() bool { +func (r *Rules) PredicatersExist() bool { return len(r.Predicaters) > 0 } -func (r *RulesExtra) PredicaterExists(addr common.Address) bool { +func (r *Rules) PredicaterExists(addr common.Address) bool { _, ok := r.Predicaters[addr] return ok } // IsPrecompileEnabled returns true if the precompile at [addr] is enabled for this rule set. -func (r *RulesExtra) IsPrecompileEnabled(addr common.Address) bool { +func (r *Rules) IsPrecompileEnabled(addr common.Address) bool { _, ok := r.Precompiles[addr] return ok } diff --git a/params/hooks_libevm.go b/params/hooks_libevm.go index 12e143bd25..b26a7a36b3 100644 --- a/params/hooks_libevm.go +++ b/params/hooks_libevm.go @@ -8,6 +8,7 @@ import ( "github.com/ava-labs/avalanchego/snow" "github.com/ava-labs/coreth/nativeasset" + "github.com/ava-labs/coreth/params/extras" "github.com/ava-labs/coreth/precompile/contract" "github.com/ava-labs/coreth/precompile/modules" "github.com/ava-labs/coreth/precompile/precompileconfig" @@ -19,6 +20,13 @@ import ( "golang.org/x/exp/maps" ) +type RulesExtra extras.Rules + +func GetRulesExtra(r Rules) *extras.Rules { + rules := payloads.PointerFromRules(&r) + return (*extras.Rules)(rules) +} + func (r RulesExtra) CanCreateContract(ac *libevm.AddressContext, gas uint64, state libevm.StateReader) (uint64, error) { return gas, nil } diff --git a/plugin/evm/block.go b/plugin/evm/block.go index d139580b0b..9003b7b7f3 100644 --- a/plugin/evm/block.go +++ b/plugin/evm/block.go @@ -18,6 +18,7 @@ import ( "github.com/ava-labs/coreth/core/rawdb" "github.com/ava-labs/coreth/core/types" "github.com/ava-labs/coreth/params" + "github.com/ava-labs/coreth/params/extras" "github.com/ava-labs/coreth/precompile/precompileconfig" "github.com/ava-labs/coreth/predicate" @@ -193,7 +194,7 @@ func (b *Block) Accept(context.Context) error { // contract.Accepter // This function assumes that the Accept function will ONLY operate on state maintained in the VM's versiondb. // This ensures that any DB operations are performed atomically with marking the block as accepted. -func (b *Block) handlePrecompileAccept(rules params.RulesExtra, sharedMemoryWriter *sharedMemoryWriter) error { +func (b *Block) handlePrecompileAccept(rules extras.Rules, sharedMemoryWriter *sharedMemoryWriter) error { // Short circuit early if there are no precompile accepters to execute if len(rules.AccepterPrecompiles) == 0 { return nil diff --git a/plugin/evm/export_tx.go b/plugin/evm/export_tx.go index 5eb16fe495..79f98af435 100644 --- a/plugin/evm/export_tx.go +++ b/plugin/evm/export_tx.go @@ -11,6 +11,7 @@ import ( "github.com/ava-labs/coreth/core/state" "github.com/ava-labs/coreth/params" + "github.com/ava-labs/coreth/params/extras" "github.com/holiman/uint256" "github.com/ava-labs/avalanchego/chains/atomic" @@ -69,7 +70,7 @@ func (utx *UnsignedExportTx) InputUTXOs() set.Set[ids.ID] { // Verify this transaction is well-formed func (utx *UnsignedExportTx) Verify( ctx *snow.Context, - rules params.RulesExtra, + rules extras.Rules, ) error { switch { case utx == nil: @@ -180,7 +181,7 @@ func (utx *UnsignedExportTx) SemanticVerify( stx *Tx, _ *Block, baseFee *big.Int, - rules params.RulesExtra, + rules extras.Rules, ) error { if err := utx.Verify(vm.ctx, rules); err != nil { return err diff --git a/plugin/evm/export_tx_test.go b/plugin/evm/export_tx_test.go index 2fcb93b78d..84f1d448bb 100644 --- a/plugin/evm/export_tx_test.go +++ b/plugin/evm/export_tx_test.go @@ -18,6 +18,7 @@ import ( "github.com/ava-labs/avalanchego/vms/components/avax" "github.com/ava-labs/avalanchego/vms/secp256k1fx" "github.com/ava-labs/coreth/params" + "github.com/ava-labs/coreth/params/extras" "github.com/ava-labs/libevm/common" "github.com/holiman/uint256" ) @@ -526,7 +527,7 @@ func TestExportTxSemanticVerify(t *testing.T) { tx *Tx signers [][]*secp256k1.PrivateKey baseFee *big.Int - rules params.RulesExtra + rules extras.Rules shouldErr bool }{ { @@ -1633,7 +1634,7 @@ func TestNewExportTx(t *testing.T) { tests := []struct { name string genesis string - rules params.RulesExtra + rules extras.Rules bal uint64 expectedBurnedAVAX uint64 }{ @@ -1806,7 +1807,7 @@ func TestNewExportTxMulticoin(t *testing.T) { tests := []struct { name string genesis string - rules params.RulesExtra + rules extras.Rules bal uint64 balmc uint64 }{ diff --git a/plugin/evm/import_tx.go b/plugin/evm/import_tx.go index 5616a92a1f..c896795706 100644 --- a/plugin/evm/import_tx.go +++ b/plugin/evm/import_tx.go @@ -12,6 +12,7 @@ import ( "github.com/ava-labs/coreth/core/state" "github.com/ava-labs/coreth/params" + "github.com/ava-labs/coreth/params/extras" "github.com/holiman/uint256" "github.com/ava-labs/avalanchego/chains/atomic" @@ -62,7 +63,7 @@ func (utx *UnsignedImportTx) InputUTXOs() set.Set[ids.ID] { // Verify this transaction is well-formed func (utx *UnsignedImportTx) Verify( ctx *snow.Context, - rules params.RulesExtra, + rules extras.Rules, ) error { switch { case utx == nil: @@ -181,7 +182,7 @@ func (utx *UnsignedImportTx) SemanticVerify( stx *Tx, parent *Block, baseFee *big.Int, - rules params.RulesExtra, + rules extras.Rules, ) error { if err := utx.Verify(vm.ctx, rules); err != nil { return err diff --git a/plugin/evm/test_tx.go b/plugin/evm/test_tx.go index e3b40164ff..134a843431 100644 --- a/plugin/evm/test_tx.go +++ b/plugin/evm/test_tx.go @@ -17,7 +17,7 @@ import ( "github.com/ava-labs/avalanchego/utils/set" "github.com/ava-labs/avalanchego/utils/wrappers" "github.com/ava-labs/coreth/core/state" - "github.com/ava-labs/coreth/params" + "github.com/ava-labs/coreth/params/extras" ) type TestUnsignedTx struct { @@ -40,7 +40,7 @@ var _ UnsignedAtomicTx = &TestUnsignedTx{} func (t *TestUnsignedTx) GasUsed(fixedFee bool) (uint64, error) { return t.GasUsedV, nil } // Verify implements the UnsignedAtomicTx interface -func (t *TestUnsignedTx) Verify(ctx *snow.Context, rules params.RulesExtra) error { return t.VerifyV } +func (t *TestUnsignedTx) Verify(ctx *snow.Context, rules extras.Rules) error { return t.VerifyV } // AtomicOps implements the UnsignedAtomicTx interface func (t *TestUnsignedTx) AtomicOps() (ids.ID, *atomic.Requests, error) { @@ -66,7 +66,7 @@ func (t *TestUnsignedTx) SignedBytes() []byte { return t.SignedBytesV } func (t *TestUnsignedTx) InputUTXOs() set.Set[ids.ID] { return t.InputUTXOsV } // SemanticVerify implements the UnsignedAtomicTx interface -func (t *TestUnsignedTx) SemanticVerify(vm *VM, stx *Tx, parent *Block, baseFee *big.Int, rules params.RulesExtra) error { +func (t *TestUnsignedTx) SemanticVerify(vm *VM, stx *Tx, parent *Block, baseFee *big.Int, rules extras.Rules) error { return t.SemanticVerifyV } diff --git a/plugin/evm/tx.go b/plugin/evm/tx.go index b2a5a95991..54f917da63 100644 --- a/plugin/evm/tx.go +++ b/plugin/evm/tx.go @@ -13,7 +13,7 @@ import ( "github.com/ava-labs/libevm/common" "github.com/ava-labs/coreth/core/state" - "github.com/ava-labs/coreth/params" + "github.com/ava-labs/coreth/params/extras" "github.com/ava-labs/avalanchego/chains/atomic" "github.com/ava-labs/avalanchego/codec" @@ -122,9 +122,9 @@ type UnsignedAtomicTx interface { // InputUTXOs returns the UTXOs this tx consumes InputUTXOs() set.Set[ids.ID] // Verify attempts to verify that the transaction is well formed - Verify(ctx *snow.Context, rules params.RulesExtra) error + Verify(ctx *snow.Context, rules extras.Rules) error // Attempts to verify this transaction with the provided state. - SemanticVerify(vm *VM, stx *Tx, parent *Block, baseFee *big.Int, rules params.RulesExtra) error + SemanticVerify(vm *VM, stx *Tx, parent *Block, baseFee *big.Int, rules extras.Rules) error // AtomicOps returns the blockchainID and set of atomic requests that // must be applied to shared memory for this transaction to be accepted. // The set of atomic requests must be returned in a consistent order. diff --git a/plugin/evm/tx_test.go b/plugin/evm/tx_test.go index 32ff051534..ef22bfa829 100644 --- a/plugin/evm/tx_test.go +++ b/plugin/evm/tx_test.go @@ -14,6 +14,7 @@ import ( "github.com/ava-labs/libevm/common" "github.com/ava-labs/coreth/params" + "github.com/ava-labs/coreth/params/extras" "github.com/ava-labs/avalanchego/chains/atomic" "github.com/ava-labs/avalanchego/ids" @@ -60,7 +61,7 @@ func TestCalculateDynamicFee(t *testing.T) { type atomicTxVerifyTest struct { ctx *snow.Context generate func(t *testing.T) UnsignedAtomicTx - rules params.RulesExtra + rules extras.Rules expectedErr string } diff --git a/plugin/evm/vm.go b/plugin/evm/vm.go index 1390ea0ab1..efd2617414 100644 --- a/plugin/evm/vm.go +++ b/plugin/evm/vm.go @@ -38,6 +38,7 @@ import ( "github.com/ava-labs/coreth/miner" "github.com/ava-labs/coreth/node" "github.com/ava-labs/coreth/params" + "github.com/ava-labs/coreth/params/extras" "github.com/ava-labs/coreth/peer" "github.com/ava-labs/coreth/plugin/evm/message" "github.com/ava-labs/coreth/triedb/hashdb" @@ -469,13 +470,13 @@ func (vm *VM) Initialize( // If the Durango is activated, activate the Warp Precompile at the same time configExtra := params.GetExtra(g.Config) if configExtra.DurangoBlockTimestamp != nil { - configExtra.PrecompileUpgrades = append(configExtra.PrecompileUpgrades, params.PrecompileUpgrade{ + configExtra.PrecompileUpgrades = append(configExtra.PrecompileUpgrades, extras.PrecompileUpgrade{ Config: warpcontract.NewDefaultConfig(configExtra.DurangoBlockTimestamp), }) } // Set the Avalanche Context on the ChainConfig - configExtra.AvalancheContext = params.AvalancheContext{ + configExtra.AvalancheContext = extras.AvalancheContext{ SnowCtx: chainCtx, } vm.syntacticBlockValidator = NewBlockValidator(extDataHashes) @@ -1698,7 +1699,7 @@ func (vm *VM) verifyTxAtTip(tx *Tx) error { // Note: verifyTx may modify [state]. If [state] needs to be properly maintained, the caller is responsible // for reverting to the correct snapshot after calling this function. If this function is called with a // throwaway state, then this is not necessary. -func (vm *VM) verifyTx(tx *Tx, parentHash common.Hash, baseFee *big.Int, state *state.StateDB, rules params.RulesExtra) error { +func (vm *VM) verifyTx(tx *Tx, parentHash common.Hash, baseFee *big.Int, state *state.StateDB, rules extras.Rules) error { parentIntf, err := vm.GetBlockInternal(context.TODO(), ids.ID(parentHash)) if err != nil { return fmt.Errorf("failed to get parent block: %w", err) @@ -1715,7 +1716,7 @@ func (vm *VM) verifyTx(tx *Tx, parentHash common.Hash, baseFee *big.Int, state * // verifyTxs verifies that [txs] are valid to be issued into a block with parent block [parentHash] // using [rules] as the current rule set. -func (vm *VM) verifyTxs(txs []*Tx, parentHash common.Hash, baseFee *big.Int, height uint64, rules params.RulesExtra) error { +func (vm *VM) verifyTxs(txs []*Tx, parentHash common.Hash, baseFee *big.Int, height uint64, rules extras.Rules) error { // Ensure that the parent was verified and inserted correctly. if !vm.blockChain.HasBlock(parentHash, height-1) { return errRejectedParent @@ -1946,12 +1947,12 @@ func (vm *VM) GetCurrentNonce(address common.Address) (uint64, error) { return state.GetNonce(address), nil } -func (vm *VM) chainConfigExtra() *params.ChainConfigExtra { +func (vm *VM) chainConfigExtra() *extras.ChainConfig { return params.GetExtra(vm.chainConfig) } // currentRules returns the chain rules for the current block. -func (vm *VM) currentRules() params.RulesExtra { +func (vm *VM) currentRules() extras.Rules { header := vm.eth.APIBackend.CurrentHeader() rules := vm.chainConfig.Rules(header.Number, params.IsMergeTODO, header.Time) return *params.GetRulesExtra(rules) diff --git a/plugin/evm/vm_warp_test.go b/plugin/evm/vm_warp_test.go index cb99e2221c..49984b7f7c 100644 --- a/plugin/evm/vm_warp_test.go +++ b/plugin/evm/vm_warp_test.go @@ -29,6 +29,7 @@ import ( "github.com/ava-labs/coreth/core/types" "github.com/ava-labs/coreth/eth/tracers" "github.com/ava-labs/coreth/params" + "github.com/ava-labs/coreth/params/extras" "github.com/ava-labs/coreth/plugin/evm/message" "github.com/ava-labs/coreth/precompile/contract" "github.com/ava-labs/coreth/precompile/contracts/warp" @@ -424,8 +425,8 @@ func TestReceiveWarpMessage(t *testing.T) { true, // RequirePrimaryNetworkSigners ) - vm.chainConfigExtra().UpgradeConfig = params.UpgradeConfig{ - PrecompileUpgrades: []params.PrecompileUpgrade{ + vm.chainConfigExtra().UpgradeConfig = extras.UpgradeConfig{ + PrecompileUpgrades: []extras.PrecompileUpgrade{ {Config: enableConfig}, {Config: disableConfig}, {Config: reEnableConfig}, diff --git a/tests/init.go b/tests/init.go index 47af1b63e2..5ec587e6d4 100644 --- a/tests/init.go +++ b/tests/init.go @@ -32,6 +32,7 @@ import ( "sort" "github.com/ava-labs/coreth/params" + "github.com/ava-labs/coreth/params/extras" "github.com/ava-labs/coreth/utils" ) @@ -177,8 +178,8 @@ var Forks = map[string]*params.ChainConfig{ PetersburgBlock: big.NewInt(0), IstanbulBlock: big.NewInt(0), }, - ¶ms.ChainConfigExtra{ - NetworkUpgrades: params.NetworkUpgrades{ + &extras.ChainConfig{ + NetworkUpgrades: extras.NetworkUpgrades{ ApricotPhase1BlockTimestamp: utils.NewUint64(0), }, }, @@ -197,8 +198,8 @@ var Forks = map[string]*params.ChainConfig{ MuirGlacierBlock: big.NewInt(0), BerlinBlock: big.NewInt(0), }, - ¶ms.ChainConfigExtra{ - NetworkUpgrades: params.NetworkUpgrades{ + &extras.ChainConfig{ + NetworkUpgrades: extras.NetworkUpgrades{ ApricotPhase1BlockTimestamp: utils.NewUint64(0), ApricotPhase2BlockTimestamp: utils.NewUint64(0), }, @@ -219,8 +220,8 @@ var Forks = map[string]*params.ChainConfig{ BerlinBlock: big.NewInt(0), LondonBlock: big.NewInt(0), }, - ¶ms.ChainConfigExtra{ - NetworkUpgrades: params.NetworkUpgrades{ + &extras.ChainConfig{ + NetworkUpgrades: extras.NetworkUpgrades{ ApricotPhase1BlockTimestamp: utils.NewUint64(0), ApricotPhase2BlockTimestamp: utils.NewUint64(0), ApricotPhase3BlockTimestamp: utils.NewUint64(0), @@ -242,8 +243,8 @@ var Forks = map[string]*params.ChainConfig{ BerlinBlock: big.NewInt(0), LondonBlock: big.NewInt(0), }, - ¶ms.ChainConfigExtra{ - NetworkUpgrades: params.NetworkUpgrades{ + &extras.ChainConfig{ + NetworkUpgrades: extras.NetworkUpgrades{ ApricotPhase1BlockTimestamp: utils.NewUint64(0), ApricotPhase2BlockTimestamp: utils.NewUint64(0), ApricotPhase3BlockTimestamp: utils.NewUint64(0), @@ -265,8 +266,8 @@ var Forks = map[string]*params.ChainConfig{ BerlinBlock: big.NewInt(0), LondonBlock: big.NewInt(0), }, - ¶ms.ChainConfigExtra{ - NetworkUpgrades: params.NetworkUpgrades{ + &extras.ChainConfig{ + NetworkUpgrades: extras.NetworkUpgrades{ ApricotPhase1BlockTimestamp: utils.NewUint64(0), ApricotPhase2BlockTimestamp: utils.NewUint64(0), ApricotPhase3BlockTimestamp: utils.NewUint64(0), @@ -289,8 +290,8 @@ var Forks = map[string]*params.ChainConfig{ BerlinBlock: big.NewInt(0), LondonBlock: big.NewInt(0), }, - ¶ms.ChainConfigExtra{ - NetworkUpgrades: params.NetworkUpgrades{ + &extras.ChainConfig{ + NetworkUpgrades: extras.NetworkUpgrades{ ApricotPhase1BlockTimestamp: utils.NewUint64(0), ApricotPhase2BlockTimestamp: utils.NewUint64(0), ApricotPhase3BlockTimestamp: utils.NewUint64(0), @@ -314,8 +315,8 @@ var Forks = map[string]*params.ChainConfig{ BerlinBlock: big.NewInt(0), LondonBlock: big.NewInt(0), }, - ¶ms.ChainConfigExtra{ - NetworkUpgrades: params.NetworkUpgrades{ + &extras.ChainConfig{ + NetworkUpgrades: extras.NetworkUpgrades{ ApricotPhase1BlockTimestamp: utils.NewUint64(0), ApricotPhase2BlockTimestamp: utils.NewUint64(0), ApricotPhase3BlockTimestamp: utils.NewUint64(0), @@ -340,8 +341,8 @@ var Forks = map[string]*params.ChainConfig{ BerlinBlock: big.NewInt(0), LondonBlock: big.NewInt(0), }, - ¶ms.ChainConfigExtra{ - NetworkUpgrades: params.NetworkUpgrades{ + &extras.ChainConfig{ + NetworkUpgrades: extras.NetworkUpgrades{ ApricotPhase1BlockTimestamp: utils.NewUint64(0), ApricotPhase2BlockTimestamp: utils.NewUint64(0), ApricotPhase3BlockTimestamp: utils.NewUint64(0), @@ -369,8 +370,8 @@ var Forks = map[string]*params.ChainConfig{ ShanghaiTime: utils.NewUint64(0), CancunTime: utils.NewUint64(0), }, - ¶ms.ChainConfigExtra{ - NetworkUpgrades: params.NetworkUpgrades{ + &extras.ChainConfig{ + NetworkUpgrades: extras.NetworkUpgrades{ ApricotPhase1BlockTimestamp: utils.NewUint64(0), ApricotPhase2BlockTimestamp: utils.NewUint64(0), ApricotPhase3BlockTimestamp: utils.NewUint64(0),