github.com/MetalBlockchain/subnet-evm@v0.4.9/precompile/fee_config_manager.go (about)

     1  // (c) 2019-2020, Ava Labs, Inc. All rights reserved.
     2  // See the file LICENSE for licensing terms.
     3  
     4  package precompile
     5  
     6  import (
     7  	"encoding/json"
     8  	"errors"
     9  	"fmt"
    10  	"math/big"
    11  
    12  	"github.com/MetalBlockchain/subnet-evm/commontype"
    13  	"github.com/MetalBlockchain/subnet-evm/vmerrs"
    14  	"github.com/ethereum/go-ethereum/common"
    15  )
    16  
    17  const (
    18  	minFeeConfigFieldKey = iota + 1
    19  	// add new fields below this
    20  	// must preserve order of these fields
    21  	gasLimitKey = iota
    22  	targetBlockRateKey
    23  	minBaseFeeKey
    24  	targetGasKey
    25  	baseFeeChangeDenominatorKey
    26  	minBlockGasCostKey
    27  	maxBlockGasCostKey
    28  	blockGasCostStepKey
    29  	// add new fields above this
    30  	numFeeConfigField = iota - 1
    31  
    32  	// [numFeeConfigField] fields in FeeConfig struct
    33  	feeConfigInputLen = common.HashLength * numFeeConfigField
    34  
    35  	SetFeeConfigGasCost     = writeGasCostPerSlot * (numFeeConfigField + 1) // plus one for setting last changed at
    36  	GetFeeConfigGasCost     = readGasCostPerSlot * numFeeConfigField
    37  	GetLastChangedAtGasCost = readGasCostPerSlot
    38  )
    39  
    40  var (
    41  	_ StatefulPrecompileConfig = &FeeConfigManagerConfig{}
    42  
    43  	// Singleton StatefulPrecompiledContract for setting fee configs by permissioned callers.
    44  	FeeConfigManagerPrecompile StatefulPrecompiledContract = createFeeConfigManagerPrecompile(FeeConfigManagerAddress)
    45  
    46  	setFeeConfigSignature              = CalculateFunctionSelector("setFeeConfig(uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256)")
    47  	getFeeConfigSignature              = CalculateFunctionSelector("getFeeConfig()")
    48  	getFeeConfigLastChangedAtSignature = CalculateFunctionSelector("getFeeConfigLastChangedAt()")
    49  
    50  	feeConfigLastChangedAtKey = common.Hash{'l', 'c', 'a'}
    51  
    52  	ErrCannotChangeFee = errors.New("non-enabled cannot change fee config")
    53  )
    54  
    55  // FeeConfigManagerConfig wraps [AllowListConfig] and uses it to implement the StatefulPrecompileConfig
    56  // interface while adding in the FeeConfigManager specific precompile address.
    57  type FeeConfigManagerConfig struct {
    58  	AllowListConfig // Config for the fee config manager allow list
    59  	UpgradeableConfig
    60  	InitialFeeConfig *commontype.FeeConfig `json:"initialFeeConfig,omitempty"` // initial fee config to be immediately activated
    61  }
    62  
    63  // NewFeeManagerConfig returns a config for a network upgrade at [blockTimestamp] that enables
    64  // FeeConfigManager with the given [admins] and [enableds] as members of the allowlist with [initialConfig] as initial fee config if specified.
    65  func NewFeeManagerConfig(blockTimestamp *big.Int, admins []common.Address, enableds []common.Address, initialConfig *commontype.FeeConfig) *FeeConfigManagerConfig {
    66  	return &FeeConfigManagerConfig{
    67  		AllowListConfig: AllowListConfig{
    68  			AllowListAdmins:  admins,
    69  			EnabledAddresses: enableds,
    70  		},
    71  		UpgradeableConfig: UpgradeableConfig{BlockTimestamp: blockTimestamp},
    72  		InitialFeeConfig:  initialConfig,
    73  	}
    74  }
    75  
    76  // NewDisableFeeManagerConfig returns config for a network upgrade at [blockTimestamp]
    77  // that disables FeeConfigManager.
    78  func NewDisableFeeManagerConfig(blockTimestamp *big.Int) *FeeConfigManagerConfig {
    79  	return &FeeConfigManagerConfig{
    80  		UpgradeableConfig: UpgradeableConfig{
    81  			BlockTimestamp: blockTimestamp,
    82  			Disable:        true,
    83  		},
    84  	}
    85  }
    86  
    87  // Address returns the address of the fee config manager contract.
    88  func (c *FeeConfigManagerConfig) Address() common.Address {
    89  	return FeeConfigManagerAddress
    90  }
    91  
    92  // Equal returns true if [s] is a [*FeeConfigManagerConfig] and it has been configured identical to [c].
    93  func (c *FeeConfigManagerConfig) Equal(s StatefulPrecompileConfig) bool {
    94  	// typecast before comparison
    95  	other, ok := (s).(*FeeConfigManagerConfig)
    96  	if !ok {
    97  		return false
    98  	}
    99  	eq := c.UpgradeableConfig.Equal(&other.UpgradeableConfig) && c.AllowListConfig.Equal(&other.AllowListConfig)
   100  	if !eq {
   101  		return false
   102  	}
   103  
   104  	if c.InitialFeeConfig == nil {
   105  		return other.InitialFeeConfig == nil
   106  	}
   107  
   108  	return c.InitialFeeConfig.Equal(other.InitialFeeConfig)
   109  }
   110  
   111  // Configure configures [state] with the desired admins based on [c].
   112  func (c *FeeConfigManagerConfig) Configure(chainConfig ChainConfig, state StateDB, blockContext BlockContext) {
   113  	// Store the initial fee config into the state when the fee config manager activates.
   114  	if c.InitialFeeConfig != nil {
   115  		if err := StoreFeeConfig(state, *c.InitialFeeConfig, blockContext); err != nil {
   116  			// This should not happen since we already checked this config with Verify()
   117  			panic(fmt.Sprintf("invalid feeConfig provided: %s", err))
   118  		}
   119  	} else {
   120  		if err := StoreFeeConfig(state, chainConfig.GetFeeConfig(), blockContext); err != nil {
   121  			// This should not happen since we already checked the chain config in the genesis creation.
   122  			panic(fmt.Sprintf("fee config should have been verified in genesis: %s", err))
   123  		}
   124  	}
   125  	c.AllowListConfig.Configure(state, FeeConfigManagerAddress)
   126  }
   127  
   128  // Contract returns the singleton stateful precompiled contract to be used for the fee manager.
   129  func (c *FeeConfigManagerConfig) Contract() StatefulPrecompiledContract {
   130  	return FeeConfigManagerPrecompile
   131  }
   132  
   133  func (c *FeeConfigManagerConfig) Verify() error {
   134  	if err := c.AllowListConfig.Verify(); err != nil {
   135  		return err
   136  	}
   137  	if c.InitialFeeConfig == nil {
   138  		return nil
   139  	}
   140  
   141  	return c.InitialFeeConfig.Verify()
   142  }
   143  
   144  // String returns a string representation of the FeeConfigManagerConfig.
   145  func (c *FeeConfigManagerConfig) String() string {
   146  	bytes, _ := json.Marshal(c)
   147  	return string(bytes)
   148  }
   149  
   150  // GetFeeConfigManagerStatus returns the role of [address] for the fee config manager list.
   151  func GetFeeConfigManagerStatus(stateDB StateDB, address common.Address) AllowListRole {
   152  	return getAllowListStatus(stateDB, FeeConfigManagerAddress, address)
   153  }
   154  
   155  // SetFeeConfigManagerStatus sets the permissions of [address] to [role] for the
   156  // fee config manager list. assumes [role] has already been verified as valid.
   157  func SetFeeConfigManagerStatus(stateDB StateDB, address common.Address, role AllowListRole) {
   158  	setAllowListRole(stateDB, FeeConfigManagerAddress, address, role)
   159  }
   160  
   161  // PackGetFeeConfigInput packs the getFeeConfig signature
   162  func PackGetFeeConfigInput() []byte {
   163  	return getFeeConfigSignature
   164  }
   165  
   166  // PackGetLastChangedAtInput packs the getFeeConfigLastChangedAt signature
   167  func PackGetLastChangedAtInput() []byte {
   168  	return getFeeConfigLastChangedAtSignature
   169  }
   170  
   171  // PackFeeConfig packs [feeConfig] without the selector into the appropriate arguments for fee config operations.
   172  func PackFeeConfig(feeConfig commontype.FeeConfig) ([]byte, error) {
   173  	//  input(feeConfig)
   174  	return packFeeConfigHelper(feeConfig, false), nil
   175  }
   176  
   177  // PackSetFeeConfig packs [feeConfig] with the selector into the appropriate arguments for setting fee config operations.
   178  func PackSetFeeConfig(feeConfig commontype.FeeConfig) ([]byte, error) {
   179  	// function selector (4 bytes) + input(feeConfig)
   180  	return packFeeConfigHelper(feeConfig, true), nil
   181  }
   182  
   183  func packFeeConfigHelper(feeConfig commontype.FeeConfig, useSelector bool) []byte {
   184  	hashes := []common.Hash{
   185  		common.BigToHash(feeConfig.GasLimit),
   186  		common.BigToHash(new(big.Int).SetUint64(feeConfig.TargetBlockRate)),
   187  		common.BigToHash(feeConfig.MinBaseFee),
   188  		common.BigToHash(feeConfig.TargetGas),
   189  		common.BigToHash(feeConfig.BaseFeeChangeDenominator),
   190  		common.BigToHash(feeConfig.MinBlockGasCost),
   191  		common.BigToHash(feeConfig.MaxBlockGasCost),
   192  		common.BigToHash(feeConfig.BlockGasCostStep),
   193  	}
   194  
   195  	if useSelector {
   196  		res := make([]byte, len(setFeeConfigSignature)+feeConfigInputLen)
   197  		packOrderedHashesWithSelector(res, setFeeConfigSignature, hashes)
   198  		return res
   199  	}
   200  
   201  	res := make([]byte, len(hashes)*common.HashLength)
   202  	packOrderedHashes(res, hashes)
   203  	return res
   204  }
   205  
   206  // UnpackFeeConfigInput attempts to unpack [input] into the arguments to the fee config precompile
   207  // assumes that [input] does not include selector (omits first 4 bytes in PackSetFeeConfigInput)
   208  func UnpackFeeConfigInput(input []byte) (commontype.FeeConfig, error) {
   209  	if len(input) != feeConfigInputLen {
   210  		return commontype.FeeConfig{}, fmt.Errorf("invalid input length for fee config input: %d", len(input))
   211  	}
   212  	feeConfig := commontype.FeeConfig{}
   213  	for i := minFeeConfigFieldKey; i <= numFeeConfigField; i++ {
   214  		listIndex := i - 1
   215  		packedElement := returnPackedHash(input, listIndex)
   216  		switch i {
   217  		case gasLimitKey:
   218  			feeConfig.GasLimit = new(big.Int).SetBytes(packedElement)
   219  		case targetBlockRateKey:
   220  			feeConfig.TargetBlockRate = new(big.Int).SetBytes(packedElement).Uint64()
   221  		case minBaseFeeKey:
   222  			feeConfig.MinBaseFee = new(big.Int).SetBytes(packedElement)
   223  		case targetGasKey:
   224  			feeConfig.TargetGas = new(big.Int).SetBytes(packedElement)
   225  		case baseFeeChangeDenominatorKey:
   226  			feeConfig.BaseFeeChangeDenominator = new(big.Int).SetBytes(packedElement)
   227  		case minBlockGasCostKey:
   228  			feeConfig.MinBlockGasCost = new(big.Int).SetBytes(packedElement)
   229  		case maxBlockGasCostKey:
   230  			feeConfig.MaxBlockGasCost = new(big.Int).SetBytes(packedElement)
   231  		case blockGasCostStepKey:
   232  			feeConfig.BlockGasCostStep = new(big.Int).SetBytes(packedElement)
   233  		default:
   234  			panic(fmt.Sprintf("unknown fee config key: %d", i))
   235  		}
   236  	}
   237  	return feeConfig, nil
   238  }
   239  
   240  // GetStoredFeeConfig returns fee config from contract storage in given state
   241  func GetStoredFeeConfig(stateDB StateDB) commontype.FeeConfig {
   242  	feeConfig := commontype.FeeConfig{}
   243  	for i := minFeeConfigFieldKey; i <= numFeeConfigField; i++ {
   244  		val := stateDB.GetState(FeeConfigManagerAddress, common.Hash{byte(i)})
   245  		switch i {
   246  		case gasLimitKey:
   247  			feeConfig.GasLimit = new(big.Int).Set(val.Big())
   248  		case targetBlockRateKey:
   249  			feeConfig.TargetBlockRate = val.Big().Uint64()
   250  		case minBaseFeeKey:
   251  			feeConfig.MinBaseFee = new(big.Int).Set(val.Big())
   252  		case targetGasKey:
   253  			feeConfig.TargetGas = new(big.Int).Set(val.Big())
   254  		case baseFeeChangeDenominatorKey:
   255  			feeConfig.BaseFeeChangeDenominator = new(big.Int).Set(val.Big())
   256  		case minBlockGasCostKey:
   257  			feeConfig.MinBlockGasCost = new(big.Int).Set(val.Big())
   258  		case maxBlockGasCostKey:
   259  			feeConfig.MaxBlockGasCost = new(big.Int).Set(val.Big())
   260  		case blockGasCostStepKey:
   261  			feeConfig.BlockGasCostStep = new(big.Int).Set(val.Big())
   262  		default:
   263  			panic(fmt.Sprintf("unknown fee config key: %d", i))
   264  		}
   265  	}
   266  	return feeConfig
   267  }
   268  
   269  func GetFeeConfigLastChangedAt(stateDB StateDB) *big.Int {
   270  	val := stateDB.GetState(FeeConfigManagerAddress, feeConfigLastChangedAtKey)
   271  	return val.Big()
   272  }
   273  
   274  // StoreFeeConfig stores given [feeConfig] and block number in the [blockContext] to the [stateDB].
   275  // A validation on [feeConfig] is done before storing.
   276  func StoreFeeConfig(stateDB StateDB, feeConfig commontype.FeeConfig, blockContext BlockContext) error {
   277  	if err := feeConfig.Verify(); err != nil {
   278  		return err
   279  	}
   280  
   281  	for i := minFeeConfigFieldKey; i <= numFeeConfigField; i++ {
   282  		var input common.Hash
   283  		switch i {
   284  		case gasLimitKey:
   285  			input = common.BigToHash(feeConfig.GasLimit)
   286  		case targetBlockRateKey:
   287  			input = common.BigToHash(new(big.Int).SetUint64(feeConfig.TargetBlockRate))
   288  		case minBaseFeeKey:
   289  			input = common.BigToHash(feeConfig.MinBaseFee)
   290  		case targetGasKey:
   291  			input = common.BigToHash(feeConfig.TargetGas)
   292  		case baseFeeChangeDenominatorKey:
   293  			input = common.BigToHash(feeConfig.BaseFeeChangeDenominator)
   294  		case minBlockGasCostKey:
   295  			input = common.BigToHash(feeConfig.MinBlockGasCost)
   296  		case maxBlockGasCostKey:
   297  			input = common.BigToHash(feeConfig.MaxBlockGasCost)
   298  		case blockGasCostStepKey:
   299  			input = common.BigToHash(feeConfig.BlockGasCostStep)
   300  		default:
   301  			panic(fmt.Sprintf("unknown fee config key: %d", i))
   302  		}
   303  		stateDB.SetState(FeeConfigManagerAddress, common.Hash{byte(i)}, input)
   304  	}
   305  
   306  	blockNumber := blockContext.Number()
   307  	if blockNumber == nil {
   308  		return fmt.Errorf("blockNumber cannot be nil")
   309  	}
   310  	stateDB.SetState(FeeConfigManagerAddress, feeConfigLastChangedAtKey, common.BigToHash(blockNumber))
   311  
   312  	return nil
   313  }
   314  
   315  // setFeeConfig checks if the caller has permissions to set the fee config.
   316  // The execution function parses [input] into FeeConfig structure and sets contract storage accordingly.
   317  func setFeeConfig(accessibleState PrecompileAccessibleState, caller common.Address, addr common.Address, input []byte, suppliedGas uint64, readOnly bool) (ret []byte, remainingGas uint64, err error) {
   318  	if remainingGas, err = deductGas(suppliedGas, SetFeeConfigGasCost); err != nil {
   319  		return nil, 0, err
   320  	}
   321  
   322  	if readOnly {
   323  		return nil, remainingGas, vmerrs.ErrWriteProtection
   324  	}
   325  
   326  	feeConfig, err := UnpackFeeConfigInput(input)
   327  	if err != nil {
   328  		return nil, remainingGas, err
   329  	}
   330  
   331  	stateDB := accessibleState.GetStateDB()
   332  	// Verify that the caller is in the allow list and therefore has the right to modify it
   333  	callerStatus := getAllowListStatus(stateDB, FeeConfigManagerAddress, caller)
   334  	if !callerStatus.IsEnabled() {
   335  		return nil, remainingGas, fmt.Errorf("%w: %s", ErrCannotChangeFee, caller)
   336  	}
   337  
   338  	if err := StoreFeeConfig(stateDB, feeConfig, accessibleState.GetBlockContext()); err != nil {
   339  		return nil, remainingGas, err
   340  	}
   341  
   342  	// Return an empty output and the remaining gas
   343  	return []byte{}, remainingGas, nil
   344  }
   345  
   346  // getFeeConfig returns the stored fee config as an output.
   347  // The execution function reads the contract state for the stored fee config and returns the output.
   348  func getFeeConfig(accessibleState PrecompileAccessibleState, caller common.Address, addr common.Address, input []byte, suppliedGas uint64, readOnly bool) (ret []byte, remainingGas uint64, err error) {
   349  	if remainingGas, err = deductGas(suppliedGas, GetFeeConfigGasCost); err != nil {
   350  		return nil, 0, err
   351  	}
   352  
   353  	feeConfig := GetStoredFeeConfig(accessibleState.GetStateDB())
   354  
   355  	output, err := PackFeeConfig(feeConfig)
   356  	if err != nil {
   357  		return nil, remainingGas, err
   358  	}
   359  
   360  	// Return the fee config as output and the remaining gas
   361  	return output, remainingGas, err
   362  }
   363  
   364  // getFeeConfigLastChangedAt returns the block number that fee config was last changed in.
   365  // The execution function reads the contract state for the stored block number and returns the output.
   366  func getFeeConfigLastChangedAt(accessibleState PrecompileAccessibleState, caller common.Address, addr common.Address, input []byte, suppliedGas uint64, readOnly bool) (ret []byte, remainingGas uint64, err error) {
   367  	if remainingGas, err = deductGas(suppliedGas, GetLastChangedAtGasCost); err != nil {
   368  		return nil, 0, err
   369  	}
   370  
   371  	lastChangedAt := GetFeeConfigLastChangedAt(accessibleState.GetStateDB())
   372  
   373  	// Return an empty output and the remaining gas
   374  	return common.BigToHash(lastChangedAt).Bytes(), remainingGas, err
   375  }
   376  
   377  // createFeeConfigManagerPrecompile returns a StatefulPrecompiledContract
   378  // with getters and setters for the chain's fee config. Access to the getters/setters
   379  // is controlled by an allow list for [precompileAddr].
   380  func createFeeConfigManagerPrecompile(precompileAddr common.Address) StatefulPrecompiledContract {
   381  	feeConfigManagerFunctions := createAllowListFunctions(precompileAddr)
   382  
   383  	setFeeConfigFunc := newStatefulPrecompileFunction(setFeeConfigSignature, setFeeConfig)
   384  	getFeeConfigFunc := newStatefulPrecompileFunction(getFeeConfigSignature, getFeeConfig)
   385  	getFeeConfigLastChangedAtFunc := newStatefulPrecompileFunction(getFeeConfigLastChangedAtSignature, getFeeConfigLastChangedAt)
   386  
   387  	feeConfigManagerFunctions = append(feeConfigManagerFunctions, setFeeConfigFunc, getFeeConfigFunc, getFeeConfigLastChangedAtFunc)
   388  	// Construct the contract with no fallback function.
   389  	contract := newStatefulPrecompileWithFunctionSelectors(nil, feeConfigManagerFunctions)
   390  	return contract
   391  }