mirror of
https://github.com/luxfi/coreth.git
synced 2026-10-30 17:00:51 +00:00
- Replace github.com/luxfi/geth/metrics with github.com/luxfi/metrics - Replace github.com/luxfi/geth/crypto with github.com/luxfi/crypto - Keep github.com/luxfi/geth/log due to API incompatibility with luxfi/log v0.1.1 - Update eth-allowed-packages.txt to reflect new imports - Update go.mod dependencies This change externalizes metrics and crypto packages to use the shared luxfi implementations across all projects. The log package remains from geth due to API differences that would require more extensive refactoring. Sync with latest ava-labs/coreth semantics and test patterns.
211 lines
8.1 KiB
Go
211 lines
8.1 KiB
Go
// Copyright (C) 2019-2025, Lux Industries, Inc. All rights reserved.
|
|
// See the file LICENSE for licensing terms.
|
|
|
|
package extras
|
|
|
|
import (
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
|
|
"github.com/luxfi/coreth/precompile/modules"
|
|
"github.com/luxfi/coreth/precompile/precompileconfig"
|
|
"github.com/luxfi/coreth/utils"
|
|
"github.com/luxfi/geth/common"
|
|
ethparams "github.com/luxfi/geth/params"
|
|
)
|
|
|
|
var errNoKey = errors.New("PrecompileUpgrade cannot be empty")
|
|
|
|
// PrecompileUpgrade is a helper struct embedded in UpgradeConfig.
|
|
// It is used to unmarshal the json into the correct precompile config type
|
|
// based on the key. Keys are defined in each precompile module, and registered in
|
|
// precompile/registry/registry.go.
|
|
type PrecompileUpgrade struct {
|
|
precompileconfig.Config
|
|
}
|
|
|
|
// UnmarshalJSON unmarshals the json into the correct precompile config type
|
|
// based on the key. Keys are defined in each precompile module, and registered in
|
|
// precompile/registry/registry.go.
|
|
// Ex: {"feeManagerConfig": {...}} where "feeManagerConfig" is the key
|
|
func (u *PrecompileUpgrade) UnmarshalJSON(data []byte) error {
|
|
raw := make(map[string]json.RawMessage)
|
|
if err := json.Unmarshal(data, &raw); err != nil {
|
|
return err
|
|
}
|
|
if len(raw) == 0 {
|
|
return errNoKey
|
|
}
|
|
if len(raw) > 1 {
|
|
return fmt.Errorf("PrecompileUpgrade must have exactly one key, got %d", len(raw))
|
|
}
|
|
for key, value := range raw {
|
|
module, ok := modules.GetPrecompileModule(key)
|
|
if !ok {
|
|
return fmt.Errorf("unknown precompile config: %s", key)
|
|
}
|
|
config := module.MakeConfig()
|
|
if err := json.Unmarshal(value, config); err != nil {
|
|
return err
|
|
}
|
|
u.Config = config
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// MarshalJSON marshal the precompile config into json based on the precompile key.
|
|
// Ex: {"feeManagerConfig": {...}} where "feeManagerConfig" is the key
|
|
func (u *PrecompileUpgrade) MarshalJSON() ([]byte, error) {
|
|
res := make(map[string]precompileconfig.Config)
|
|
res[u.Key()] = u.Config
|
|
return json.Marshal(res)
|
|
}
|
|
|
|
// verifyPrecompileUpgrades checks [c.PrecompileUpgrades] is well formed:
|
|
// - [upgrades] must specify exactly one key per PrecompileUpgrade
|
|
// - the specified blockTimestamps must monotonically increase
|
|
// - 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 *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 {
|
|
blockTimestamp uint64
|
|
disabled bool
|
|
}
|
|
|
|
lastPrecompileUpgrades := make(map[string]lastUpgradeData)
|
|
|
|
// next range over upgrades to verify correct use of disabled and blockTimestamps.
|
|
// previousUpgradeTimestamp is used to verify monotonically increasing timestamps.
|
|
var previousUpgradeTimestamp *uint64
|
|
for i, upgrade := range c.PrecompileUpgrades {
|
|
key := upgrade.Key()
|
|
|
|
// lastUpgradeByKey is the previous processed upgrade for this precompile key.
|
|
lastUpgradeByKey, ok := lastPrecompileUpgrades[key]
|
|
var (
|
|
disabled bool
|
|
lastTimestamp *uint64
|
|
)
|
|
if !ok {
|
|
disabled = true
|
|
lastTimestamp = nil
|
|
} else {
|
|
disabled = lastUpgradeByKey.disabled
|
|
lastTimestamp = utils.NewUint64(lastUpgradeByKey.blockTimestamp)
|
|
}
|
|
upgradeTimestamp := upgrade.Timestamp()
|
|
|
|
if upgradeTimestamp == nil {
|
|
return fmt.Errorf("PrecompileUpgrade (%s) at [%d]: block timestamp cannot be nil ", key, i)
|
|
}
|
|
// Verify specified timestamps are monotonically increasing across all precompile keys.
|
|
// Note: It is OK for multiple configs of DIFFERENT keys to specify the same timestamp.
|
|
if previousUpgradeTimestamp != nil && *upgradeTimestamp < *previousUpgradeTimestamp {
|
|
return fmt.Errorf("PrecompileUpgrade (%s) at [%d]: config block timestamp (%v) < previous timestamp (%v)", key, i, *upgradeTimestamp, *previousUpgradeTimestamp)
|
|
}
|
|
|
|
if disabled == upgrade.IsDisabled() {
|
|
return fmt.Errorf("PrecompileUpgrade (%s) at [%d]: disable should be [%v]", key, i, !disabled)
|
|
}
|
|
// Verify specified timestamps are monotonically increasing across same precompile keys.
|
|
// Note: It is NOT OK for multiple configs of the SAME key to specify the same timestamp.
|
|
if lastTimestamp != nil && *upgradeTimestamp <= *lastTimestamp {
|
|
return fmt.Errorf("PrecompileUpgrade (%s) at [%d]: config block timestamp (%v) <= previous timestamp (%v) of same key", key, i, *upgradeTimestamp, *lastTimestamp)
|
|
}
|
|
|
|
if err := upgrade.Verify(c); err != nil {
|
|
return err
|
|
}
|
|
|
|
lastPrecompileUpgrades[key] = lastUpgradeData{
|
|
disabled: upgrade.IsDisabled(),
|
|
blockTimestamp: *upgradeTimestamp,
|
|
}
|
|
|
|
previousUpgradeTimestamp = upgradeTimestamp
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// GetActivePrecompileConfig returns the most recent precompile config corresponding to [address].
|
|
// If none have occurred, returns nil.
|
|
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
|
|
}
|
|
return configs[len(configs)-1] // return the most recent config
|
|
}
|
|
|
|
// 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 *ChainConfig) GetActivatingPrecompileConfigs(address common.Address, from *uint64, to uint64, upgrades []PrecompileUpgrade) []precompileconfig.Config {
|
|
// Get key from address.
|
|
module, ok := modules.GetPrecompileModuleByAddress(address)
|
|
if !ok {
|
|
return nil
|
|
}
|
|
configs := make([]precompileconfig.Config, 0)
|
|
key := module.ConfigKey
|
|
// Loop over all upgrades checking for the requested precompile config.
|
|
for _, upgrade := range upgrades {
|
|
if upgrade.Key() == key {
|
|
// Check if the precompile activates in the specified range.
|
|
if IsForkTransition(upgrade.Timestamp(), from, to) {
|
|
configs = append(configs, upgrade.Config)
|
|
}
|
|
}
|
|
}
|
|
return configs
|
|
}
|
|
|
|
// checkPrecompilesCompatible checks if [precompileUpgrades] are compatible with [c] at [headTimestamp].
|
|
// Returns a ConfigCompatError if upgrades already activated at [headTimestamp] are missing from
|
|
// [precompileUpgrades]. Upgrades not already activated may be modified or absent from [precompileUpgrades].
|
|
// Returns nil if [precompileUpgrades] is compatible with [c].
|
|
// Assumes given timestamp is the last accepted block timestamp.
|
|
// This ensures that as long as the node has not accepted a block with a different rule set it will allow a
|
|
// new upgrade to be applied as long as it activates after the last accepted block.
|
|
//
|
|
//nolint:unused
|
|
func (c *ChainConfig) checkPrecompilesCompatible(precompileUpgrades []PrecompileUpgrade, time uint64) *ethparams.ConfigCompatError {
|
|
for _, module := range modules.RegisteredModules() {
|
|
if err := c.checkPrecompileCompatible(module.Address, precompileUpgrades, time); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// checkPrecompileCompatible verifies that the precompile specified by [address] is compatible between [c]
|
|
// and [precompileUpgrades] at [headTimestamp].
|
|
// Returns an error if upgrades already activated at [headTimestamp] are missing from [precompileUpgrades].
|
|
// Upgrades that have already gone into effect cannot be modified or absent from [precompileUpgrades].
|
|
//
|
|
//nolint:unused
|
|
func (c *ChainConfig) checkPrecompileCompatible(address common.Address, precompileUpgrades []PrecompileUpgrade, time uint64) *ethparams.ConfigCompatError {
|
|
// All upgrades are always activated from the beginning
|
|
// No compatibility checking needed for Lux infrastructure
|
|
// Skip checking activeUpgrades and newUpgrades since we don't need compatibility checks
|
|
|
|
return nil
|
|
}
|
|
|
|
// EnabledStatefulPrecompiles returns current stateful precompile configs that are enabled at [blockTimestamp].
|
|
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() {
|
|
statefulPrecompileConfigs[module.ConfigKey] = config
|
|
}
|
|
}
|
|
|
|
return statefulPrecompileConfigs
|
|
}
|