From 1fdc23e7711d539a0d6042c98c14445cf5d0d905 Mon Sep 17 00:00:00 2001 From: Ceyhun Onur Date: Tue, 20 Dec 2022 21:28:45 +0300 Subject: [PATCH 01/23] rework on panics in precompiles --- accounts/abi/bind/precompile_template.go | 35 ++++++++---- core/genesis.go | 5 +- core/state_processor.go | 6 +- miner/worker.go | 5 +- params/precompile_config.go | 9 ++- precompile/allow_list.go | 10 +++- precompile/contract.go | 11 ++-- precompile/contract_deployer_allow_list.go | 4 +- precompile/contract_native_minter.go | 15 +++-- precompile/fee_config_manager.go | 32 +++++++---- precompile/reward_manager.go | 65 +++++++++------------- precompile/stateful_precompile_config.go | 6 +- precompile/tx_allow_list.go | 4 +- precompile/utils.go | 10 ++-- 14 files changed, 126 insertions(+), 91 deletions(-) diff --git a/accounts/abi/bind/precompile_template.go b/accounts/abi/bind/precompile_template.go index 2f4cd39ad1..596d96c351 100644 --- a/accounts/abi/bind/precompile_template.go +++ b/accounts/abi/bind/precompile_template.go @@ -46,6 +46,7 @@ Typically, custom codes are required in only those areas. package precompile import ( + "encoding/json" "math/big" "errors" "fmt" @@ -75,6 +76,7 @@ var ( _ = big.NewInt _ = strings.NewReader _ = fmt.Printf + _ = json.Unmarshal ) {{$contract := .Contract}} @@ -148,7 +150,10 @@ func init() { } {{.Contract.Type}}ABI = parsed - {{.Contract.Type}}Precompile = create{{.Contract.Type}}Precompile({{.Contract.Type}}Address) + {{.Contract.Type}}Precompile, err = create{{.Contract.Type}}Precompile({{.Contract.Type}}Address) + if err != nil { + panic(err) + } } // New{{.Contract.Type}}Config returns a config for a network upgrade at [blockTimestamp] that enables @@ -198,9 +203,10 @@ func (c *{{.Contract.Type}}Config) Address() common.Address { } // Configure configures [state] with the initial configuration. -func (c *{{.Contract.Type}}Config) Configure(_ ChainConfig, state StateDB, _ BlockContext) { +func (c *{{.Contract.Type}}Config) Configure(_ ChainConfig, state StateDB, _ BlockContext) error { {{if .Contract.AllowList}}c.AllowListConfig.Configure(state, {{.Contract.Type}}Address){{end}} // CUSTOM CODE STARTS HERE + return nil } // Contract returns the singleton stateful precompiled contract to be used for {{.Contract.Type}}. @@ -404,27 +410,32 @@ func {{decapitalise $contract.Type}}Fallback (accessibleState PrecompileAccessib // create{{.Contract.Type}}Precompile returns a StatefulPrecompiledContract with getters and setters for the precompile. {{if .Contract.AllowList}} // Access to the getters/setters is controlled by an allow list for [precompileAddr].{{end}} -func create{{.Contract.Type}}Precompile(precompileAddr common.Address) StatefulPrecompiledContract { +func create{{.Contract.Type}}Precompile(precompileAddr common.Address) (StatefulPrecompiledContract, error) { var functions []*statefulPrecompileFunction {{- if .Contract.AllowList}} functions = append(functions, createAllowListFunctions(precompileAddr)...) {{- end}} - {{range .Contract.Funcs}} - method{{.Normalized.Name}}, ok := {{$contract.Type}}ABI.Methods["{{.Original.Name}}"] - if !ok{ - panic("given method does not exist in the ABI") + abiFunctionMap := map[string]RunStatefulPrecompileFunc{ + {{- range .Contract.Funcs}} + "{{.Original.Name}}": {{decapitalise .Normalized.Name}}, + {{- end}} + } + + for name, function := range abiFunctionMap { + method, ok := {{$contract.Type}}ABI.Methods[name] + if !ok { + return nil, fmt.Errorf("given method (%s) does not exist in the ABI", name) + } + functions = append(functions, newStatefulPrecompileFunction(method.ID, function)) } - functions = append(functions, newStatefulPrecompileFunction(method{{.Normalized.Name}}.ID, {{decapitalise .Normalized.Name}})) - {{end}} {{- if .Contract.Fallback}} // Construct the contract with the fallback function. - contract := newStatefulPrecompileWithFunctionSelectors({{decapitalise $contract.Type}}Fallback, functions) + return NewStatefulPrecompileContract({{decapitalise $contract.Type}}Fallback, functions) {{- else}} // Construct the contract with no fallback function. - contract := newStatefulPrecompileWithFunctionSelectors(nil, functions) + return NewStatefulPrecompileContract(nil, functions) {{- end}} - return contract } ` diff --git a/core/genesis.go b/core/genesis.go index eb88bc82f4..1ab970ad2e 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -307,7 +307,10 @@ func (g *Genesis) ToBlock(db ethdb.Database) *types.Block { } // Configure any stateful precompiles that should be enabled in the genesis. - g.Config.CheckConfigurePrecompiles(nil, types.NewBlockWithHeader(head), statedb) + err = g.Config.ConfigurePrecompiles(nil, types.NewBlockWithHeader(head), statedb) + if err != nil { + panic(fmt.Sprintf("unable to configure precompiles in genesis block: %v", err)) + } // Do custom allocation after airdrop in case an address shows up in standard // allocation diff --git a/core/state_processor.go b/core/state_processor.go index 2b28f8b082..6ae2bddbbf 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -78,7 +78,11 @@ func (p *StateProcessor) Process(block *types.Block, parent *types.Header, state ) // Configure any stateful precompiles that should go into effect during this block. - p.config.CheckConfigurePrecompiles(new(big.Int).SetUint64(parent.Time), block, statedb) + err := p.config.ConfigurePrecompiles(new(big.Int).SetUint64(parent.Time), block, statedb) + // ASK: Should we panic instead? + if err != nil { + return nil, nil, 0, fmt.Errorf("could not configure precompiles: %w", err) + } blockContext := NewEVMBlockContext(header, p.bc, nil) vmenv := vm.NewEVM(blockContext, vm.TxContext{}, statedb, p.config, cfg) diff --git a/miner/worker.go b/miner/worker.go index 050cf663be..976940a243 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -184,7 +184,10 @@ func (w *worker) commitNewWork() (*types.Block, error) { return nil, fmt.Errorf("failed to create new current environment: %w", err) } // Configure any stateful precompiles that should go into effect during this block. - w.chainConfig.CheckConfigurePrecompiles(new(big.Int).SetUint64(parent.Time()), types.NewBlockWithHeader(header), env.state) + err = w.chainConfig.ConfigurePrecompiles(new(big.Int).SetUint64(parent.Time()), types.NewBlockWithHeader(header), env.state) + if err != nil { + return nil, fmt.Errorf("failed to configure precompiles: %w", err) + } // Fill the block with all available pending transactions. pending := w.eth.TxPool().Pending(true) diff --git a/params/precompile_config.go b/params/precompile_config.go index daa457b03b..02788afd69 100644 --- a/params/precompile_config.go +++ b/params/precompile_config.go @@ -346,13 +346,13 @@ func (c *ChainConfig) EnabledStatefulPrecompiles(blockTimestamp *big.Int) []prec return statefulPrecompileConfigs } -// CheckConfigurePrecompiles checks if any of the precompiles specified by the chain config are enabled or disabled by the block +// ConfigurePrecompiles checks if any of the precompiles specified by the chain config are enabled or disabled by the block // transition from [parentTimestamp] to the timestamp set in [blockContext]. If this is the case, it calls [Configure] // or [Deconfigure] to apply the necessary state transitions for the upgrade. // This function is called: // - within genesis setup to configure the starting state for precompiles enabled at genesis, // - during block processing to update the state before processing the given block. -func (c *ChainConfig) CheckConfigurePrecompiles(parentTimestamp *big.Int, blockContext precompile.BlockContext, statedb precompile.StateDB) { +func (c *ChainConfig) ConfigurePrecompiles(parentTimestamp *big.Int, blockContext precompile.BlockContext, statedb precompile.StateDB) error { blockTimestamp := blockContext.Timestamp() for _, key := range precompileKeys { // Note: configure precompiles in a deterministic order. for _, config := range c.getActivatingPrecompileConfigs(parentTimestamp, blockTimestamp, key, c.PrecompileUpgrades) { @@ -368,8 +368,11 @@ func (c *ChainConfig) CheckConfigurePrecompiles(parentTimestamp *big.Int, blockC statedb.Finalise(true) } else { log.Info("Activating new precompile", "name", key, "config", config) - precompile.Configure(c, blockContext, config, statedb) + if err := precompile.Configure(c, blockContext, config, statedb); err != nil { + return err + } } } } + return nil } diff --git a/precompile/allow_list.go b/precompile/allow_list.go index e411b5eba4..c580106db8 100644 --- a/precompile/allow_list.go +++ b/precompile/allow_list.go @@ -46,13 +46,14 @@ type AllowListConfig struct { // Configure initializes the address space of [precompileAddr] by initializing the role of each of // the addresses in [AllowListAdmins]. -func (c *AllowListConfig) Configure(state StateDB, precompileAddr common.Address) { +func (c *AllowListConfig) Configure(state StateDB, precompileAddr common.Address) error { for _, enabledAddr := range c.EnabledAddresses { setAllowListRole(state, precompileAddr, enabledAddr, AllowListEnabled) } for _, adminAddr := range c.AllowListAdmins { setAllowListRole(state, precompileAddr, adminAddr, AllowListAdmin) } + return nil } // Equal returns true iff [other] has the same admins in the same order in its allow list. @@ -219,7 +220,12 @@ func createReadAllowList(precompileAddr common.Address) RunStatefulPrecompileFun func createAllowListPrecompile(precompileAddr common.Address) StatefulPrecompiledContract { // Construct the contract with no fallback function. allowListFuncs := createAllowListFunctions(precompileAddr) - contract := newStatefulPrecompileWithFunctionSelectors(nil, allowListFuncs) + contract, err := NewStatefulPrecompileContract(nil, allowListFuncs) + // Change this to be returned as an error after refactoring this precompile + // to use the new precompile template. + if err != nil { + panic(err) + } return contract } diff --git a/precompile/contract.go b/precompile/contract.go index 0e2d720273..9dadb02ab9 100644 --- a/precompile/contract.go +++ b/precompile/contract.go @@ -98,9 +98,9 @@ type statefulPrecompileWithFunctionSelectors struct { functions map[string]*statefulPrecompileFunction } -// newStatefulPrecompileWithFunctionSelectors generates new StatefulPrecompile using [functions] as the available functions and [fallback] +// NewStatefulPrecompileContract generates new StatefulPrecompile using [functions] as the available functions and [fallback] // as an optional fallback if there is no input data. Note: the selector of [fallback] will be ignored, so it is required to be left empty. -func newStatefulPrecompileWithFunctionSelectors(fallback RunStatefulPrecompileFunc, functions []*statefulPrecompileFunction) StatefulPrecompiledContract { +func NewStatefulPrecompileContract(fallback RunStatefulPrecompileFunc, functions []*statefulPrecompileFunction) (StatefulPrecompiledContract, error) { // Construct the contract and populate [functions]. contract := &statefulPrecompileWithFunctionSelectors{ fallback: fallback, @@ -109,12 +109,15 @@ func newStatefulPrecompileWithFunctionSelectors(fallback RunStatefulPrecompileFu for _, function := range functions { _, exists := contract.functions[string(function.selector)] if exists { - panic(fmt.Errorf("cannot create stateful precompile with duplicated function selector: %q", function.selector)) + return nil, fmt.Errorf("cannot create stateful precompile with duplicated function selector: %q", function.selector) + } + if function == nil { + return nil, fmt.Errorf("cannot create stateful precompile with nil function, selector: %q", function.selector) } contract.functions[string(function.selector)] = function } - return contract + return contract, nil } // Run selects the function using the 4 byte function selector at the start of the input and executes the underlying function on the diff --git a/precompile/contract_deployer_allow_list.go b/precompile/contract_deployer_allow_list.go index 7d42a270b9..11df6ff3fe 100644 --- a/precompile/contract_deployer_allow_list.go +++ b/precompile/contract_deployer_allow_list.go @@ -52,8 +52,8 @@ func (c *ContractDeployerAllowListConfig) Address() common.Address { } // Configure configures [state] with the desired admins based on [c]. -func (c *ContractDeployerAllowListConfig) Configure(_ ChainConfig, state StateDB, _ BlockContext) { - c.AllowListConfig.Configure(state, ContractDeployerAllowListAddress) +func (c *ContractDeployerAllowListConfig) Configure(_ ChainConfig, state StateDB, _ BlockContext) error { + return c.AllowListConfig.Configure(state, ContractDeployerAllowListAddress) } // Contract returns the singleton stateful precompiled contract to be used for the allow list. diff --git a/precompile/contract_native_minter.go b/precompile/contract_native_minter.go index 2da1b3bbaa..26ccaf8e68 100644 --- a/precompile/contract_native_minter.go +++ b/precompile/contract_native_minter.go @@ -71,7 +71,7 @@ func (c *ContractNativeMinterConfig) Address() common.Address { } // Configure configures [state] with the desired admins based on [c]. -func (c *ContractNativeMinterConfig) Configure(_ ChainConfig, state StateDB, _ BlockContext) { +func (c *ContractNativeMinterConfig) Configure(_ ChainConfig, state StateDB, _ BlockContext) error { for to, amount := range c.InitialMint { if amount != nil { bigIntAmount := (*big.Int)(amount) @@ -79,7 +79,7 @@ func (c *ContractNativeMinterConfig) Configure(_ ChainConfig, state StateDB, _ B } } - c.AllowListConfig.Configure(state, ContractNativeMinterAddress) + return c.AllowListConfig.Configure(state, ContractNativeMinterAddress) } // Contract returns the singleton stateful precompiled contract to be used for the native minter. @@ -157,12 +157,12 @@ func SetContractNativeMinterStatus(stateDB StateDB, address common.Address, role func PackMintInput(address common.Address, amount *big.Int) ([]byte, error) { // function selector (4 bytes) + input(hash for address + hash for amount) res := make([]byte, selectorLen+mintInputLen) - packOrderedHashesWithSelector(res, mintSignature, []common.Hash{ + err := packOrderedHashesWithSelector(res, mintSignature, []common.Hash{ address.Hash(), common.BigToHash(amount), }) - return res, nil + return res, err } // UnpackMintInput attempts to unpack [input] into the arguments to the mint precompile @@ -217,6 +217,11 @@ func createNativeMinterPrecompile(precompileAddr common.Address) StatefulPrecomp enabledFuncs = append(enabledFuncs, mintFunc) // Construct the contract with no fallback function. - contract := newStatefulPrecompileWithFunctionSelectors(nil, enabledFuncs) + contract, err := NewStatefulPrecompileContract(nil, enabledFuncs) + // Change this to be returned as an error after refactoring this precompile + // to use the new precompile template. + if err != nil { + panic(err) + } return contract } diff --git a/precompile/fee_config_manager.go b/precompile/fee_config_manager.go index 3436ba360c..97bdbfa327 100644 --- a/precompile/fee_config_manager.go +++ b/precompile/fee_config_manager.go @@ -109,20 +109,20 @@ func (c *FeeConfigManagerConfig) Equal(s StatefulPrecompileConfig) bool { } // Configure configures [state] with the desired admins based on [c]. -func (c *FeeConfigManagerConfig) Configure(chainConfig ChainConfig, state StateDB, blockContext BlockContext) { +func (c *FeeConfigManagerConfig) Configure(chainConfig ChainConfig, state StateDB, blockContext BlockContext) error { // Store the initial fee config into the state when the fee config manager activates. if c.InitialFeeConfig != nil { if err := StoreFeeConfig(state, *c.InitialFeeConfig, blockContext); err != nil { // This should not happen since we already checked this config with Verify() - panic(fmt.Sprintf("invalid feeConfig provided: %s", err)) + return fmt.Errorf("invalid feeConfig provided: %w", err) } } else { if err := StoreFeeConfig(state, chainConfig.GetFeeConfig(), blockContext); err != nil { // This should not happen since we already checked the chain config in the genesis creation. - panic(fmt.Sprintf("fee config should have been verified in genesis: %s", err)) + return fmt.Errorf("invalid feeConfig provided in chainConfig: %w", err) } } - c.AllowListConfig.Configure(state, FeeConfigManagerAddress) + return c.AllowListConfig.Configure(state, FeeConfigManagerAddress) } // Contract returns the singleton stateful precompiled contract to be used for the fee manager. @@ -171,16 +171,16 @@ func PackGetLastChangedAtInput() []byte { // PackFeeConfig packs [feeConfig] without the selector into the appropriate arguments for fee config operations. func PackFeeConfig(feeConfig commontype.FeeConfig) ([]byte, error) { // input(feeConfig) - return packFeeConfigHelper(feeConfig, false), nil + return packFeeConfigHelper(feeConfig, false) } // PackSetFeeConfig packs [feeConfig] with the selector into the appropriate arguments for setting fee config operations. func PackSetFeeConfig(feeConfig commontype.FeeConfig) ([]byte, error) { // function selector (4 bytes) + input(feeConfig) - return packFeeConfigHelper(feeConfig, true), nil + return packFeeConfigHelper(feeConfig, true) } -func packFeeConfigHelper(feeConfig commontype.FeeConfig, useSelector bool) []byte { +func packFeeConfigHelper(feeConfig commontype.FeeConfig, useSelector bool) ([]byte, error) { hashes := []common.Hash{ common.BigToHash(feeConfig.GasLimit), common.BigToHash(new(big.Int).SetUint64(feeConfig.TargetBlockRate)), @@ -194,13 +194,13 @@ func packFeeConfigHelper(feeConfig commontype.FeeConfig, useSelector bool) []byt if useSelector { res := make([]byte, len(setFeeConfigSignature)+feeConfigInputLen) - packOrderedHashesWithSelector(res, setFeeConfigSignature, hashes) - return res + err := packOrderedHashesWithSelector(res, setFeeConfigSignature, hashes) + return res, err } res := make([]byte, len(hashes)*common.HashLength) - packOrderedHashes(res, hashes) - return res + err := packOrderedHashes(res, hashes) + return res, err } // UnpackFeeConfigInput attempts to unpack [input] into the arguments to the fee config precompile @@ -231,6 +231,7 @@ func UnpackFeeConfigInput(input []byte) (commontype.FeeConfig, error) { case blockGasCostStepKey: feeConfig.BlockGasCostStep = new(big.Int).SetBytes(packedElement) default: + // this should not ever happen. keep this as panic. panic(fmt.Sprintf("unknown fee config key: %d", i)) } } @@ -260,6 +261,7 @@ func GetStoredFeeConfig(stateDB StateDB) commontype.FeeConfig { case blockGasCostStepKey: feeConfig.BlockGasCostStep = new(big.Int).Set(val.Big()) default: + // this should not ever happen. keep this as panic. panic(fmt.Sprintf("unknown fee config key: %d", i)) } } @@ -298,6 +300,7 @@ func StoreFeeConfig(stateDB StateDB, feeConfig commontype.FeeConfig, blockContex case blockGasCostStepKey: input = common.BigToHash(feeConfig.BlockGasCostStep) default: + // this should not ever happen. keep this as panic. panic(fmt.Sprintf("unknown fee config key: %d", i)) } stateDB.SetState(FeeConfigManagerAddress, common.Hash{byte(i)}, input) @@ -386,6 +389,11 @@ func createFeeConfigManagerPrecompile(precompileAddr common.Address) StatefulPre feeConfigManagerFunctions = append(feeConfigManagerFunctions, setFeeConfigFunc, getFeeConfigFunc, getFeeConfigLastChangedAtFunc) // Construct the contract with no fallback function. - contract := newStatefulPrecompileWithFunctionSelectors(nil, feeConfigManagerFunctions) + contract, err := NewStatefulPrecompileContract(nil, feeConfigManagerFunctions) + // Change this to be returned as an error after refactoring this precompile + // to use the new precompile template. + if err != nil { + panic(err) + } return contract } diff --git a/precompile/reward_manager.go b/precompile/reward_manager.go index f57b0f72a8..7262efa0b8 100644 --- a/precompile/reward_manager.go +++ b/precompile/reward_manager.go @@ -76,7 +76,7 @@ func (c *InitialRewardConfig) Equal(other *InitialRewardConfig) bool { return c.AllowFeeRecipients == other.AllowFeeRecipients && c.RewardAddress == other.RewardAddress } -func (i *InitialRewardConfig) Configure(state StateDB) { +func (i *InitialRewardConfig) Configure(state StateDB) error { // enable allow fee recipients if i.AllowFeeRecipients { EnableAllowFeeRecipients(state) @@ -86,10 +86,9 @@ func (i *InitialRewardConfig) Configure(state StateDB) { DisableFeeRewards(state) } else { // set reward address - if err := StoreRewardAddress(state, i.RewardAddress); err != nil { - panic(err) - } + return StoreRewardAddress(state, i.RewardAddress) } + return nil } // RewardManagerConfig implements the StatefulPrecompileConfig @@ -106,7 +105,10 @@ func init() { panic(err) } RewardManagerABI = parsed - RewardManagerPrecompile = createRewardManagerPrecompile(RewardManagerAddress) + RewardManagerPrecompile, err = createRewardManagerPrecompile(RewardManagerAddress) + if err != nil { + panic(err) + } } // NewRewardManagerConfig returns a config for a network upgrade at [blockTimestamp] that enables @@ -161,11 +163,11 @@ func (c *RewardManagerConfig) Address() common.Address { } // Configure configures [state] with the initial configuration. -func (c *RewardManagerConfig) Configure(chainConfig ChainConfig, state StateDB, _ BlockContext) { +func (c *RewardManagerConfig) Configure(chainConfig ChainConfig, state StateDB, _ BlockContext) error { c.AllowListConfig.Configure(state, RewardManagerAddress) // configure the RewardManager with the given initial configuration if c.InitialRewardConfig != nil { - c.InitialRewardConfig.Configure(state) + return c.InitialRewardConfig.Configure(state) } else if chainConfig.AllowedFeeRecipients() { // configure the RewardManager according to chainConfig EnableAllowFeeRecipients(state) @@ -175,6 +177,7 @@ func (c *RewardManagerConfig) Configure(chainConfig ChainConfig, state StateDB, // default to disabling rewards DisableFeeRewards(state) } + return nil } // Contract returns the singleton stateful precompiled contract to be used for RewardManager. @@ -419,41 +422,25 @@ func disableRewards(accessibleState PrecompileAccessibleState, caller common.Add // createRewardManagerPrecompile returns a StatefulPrecompiledContract with getters and setters for the precompile. // Access to the getters/setters is controlled by an allow list for [precompileAddr]. -func createRewardManagerPrecompile(precompileAddr common.Address) StatefulPrecompiledContract { +func createRewardManagerPrecompile(precompileAddr common.Address) (StatefulPrecompiledContract, error) { var functions []*statefulPrecompileFunction functions = append(functions, createAllowListFunctions(precompileAddr)...) - - methodAllowFeeRecipients, ok := RewardManagerABI.Methods["allowFeeRecipients"] - if !ok { - panic("given method does not exist in the ABI") - } - functions = append(functions, newStatefulPrecompileFunction(methodAllowFeeRecipients.ID, allowFeeRecipients)) - - methodAreFeeRecipientsAllowed, ok := RewardManagerABI.Methods["areFeeRecipientsAllowed"] - if !ok { - panic("given method does not exist in the ABI") - } - functions = append(functions, newStatefulPrecompileFunction(methodAreFeeRecipientsAllowed.ID, areFeeRecipientsAllowed)) - - methodCurrentRewardAddress, ok := RewardManagerABI.Methods["currentRewardAddress"] - if !ok { - panic("given method does not exist in the ABI") - } - functions = append(functions, newStatefulPrecompileFunction(methodCurrentRewardAddress.ID, currentRewardAddress)) - - methodDisableRewards, ok := RewardManagerABI.Methods["disableRewards"] - if !ok { - panic("given method does not exist in the ABI") - } - functions = append(functions, newStatefulPrecompileFunction(methodDisableRewards.ID, disableRewards)) - - methodSetRewardAddress, ok := RewardManagerABI.Methods["setRewardAddress"] - if !ok { - panic("given method does not exist in the ABI") + abiFunctionMap := map[string]RunStatefulPrecompileFunc{ + "allowFeeRecipients": allowFeeRecipients, + "areFeeRecipientsAllowed": areFeeRecipientsAllowed, + "currentRewardAddress": currentRewardAddress, + "disableRewards": disableRewards, + "setRewardAddress": setRewardAddress, + } + + for name, function := range abiFunctionMap { + method, ok := RewardManagerABI.Methods[name] + if !ok { + return nil, fmt.Errorf("given method (%s) does not exist in the ABI", name) + } + functions = append(functions, newStatefulPrecompileFunction(method.ID, function)) } - functions = append(functions, newStatefulPrecompileFunction(methodSetRewardAddress.ID, setRewardAddress)) // Construct the contract with no fallback function. - contract := newStatefulPrecompileWithFunctionSelectors(nil, functions) - return contract + return NewStatefulPrecompileContract(nil, functions) } diff --git a/precompile/stateful_precompile_config.go b/precompile/stateful_precompile_config.go index 7db30060e4..6955b8d448 100644 --- a/precompile/stateful_precompile_config.go +++ b/precompile/stateful_precompile_config.go @@ -32,7 +32,7 @@ type StatefulPrecompileConfig interface { // Configure is called on the first block where the stateful precompile should be enabled. This // provides the config the ability to set its initial state and should only modify the state within // its own address space. - Configure(ChainConfig, StateDB, BlockContext) + Configure(ChainConfig, StateDB, BlockContext) error // Contract returns a thread-safe singleton that can be used as the StatefulPrecompiledContract when // this config is enabled. Contract() StatefulPrecompiledContract @@ -45,7 +45,7 @@ type StatefulPrecompileConfig interface { // Configure sets the nonce and code to non-empty values then calls Configure on [precompileConfig] to make the necessary // state update to enable the StatefulPrecompile. // Assumes that [precompileConfig] is non-nil. -func Configure(chainConfig ChainConfig, blockContext BlockContext, precompileConfig StatefulPrecompileConfig, state StateDB) { +func Configure(chainConfig ChainConfig, blockContext BlockContext, precompileConfig StatefulPrecompileConfig, state StateDB) error { // Set the nonce of the precompile's address (as is done when a contract is created) to ensure // that it is marked as non-empty and will not be cleaned up when the statedb is finalized. state.SetNonce(precompileConfig.Address(), 1) @@ -53,5 +53,5 @@ func Configure(chainConfig ChainConfig, blockContext BlockContext, precompileCon // can be called from within Solidity contracts. Solidity adds a check before invoking a contract to ensure // that it does not attempt to invoke a non-existent contract. state.SetCode(precompileConfig.Address(), []byte{0x1}) - precompileConfig.Configure(chainConfig, state, blockContext) + return precompileConfig.Configure(chainConfig, state, blockContext) } diff --git a/precompile/tx_allow_list.go b/precompile/tx_allow_list.go index c67e07011f..4ab39a8f04 100644 --- a/precompile/tx_allow_list.go +++ b/precompile/tx_allow_list.go @@ -55,8 +55,8 @@ func (c *TxAllowListConfig) Address() common.Address { } // Configure configures [state] with the desired admins based on [c]. -func (c *TxAllowListConfig) Configure(_ ChainConfig, state StateDB, _ BlockContext) { - c.AllowListConfig.Configure(state, TxAllowListAddress) +func (c *TxAllowListConfig) Configure(_ ChainConfig, state StateDB, _ BlockContext) error { + return c.AllowListConfig.Configure(state, TxAllowListAddress) } // Contract returns the singleton stateful precompiled contract to be used for the allow list. diff --git a/precompile/utils.go b/precompile/utils.go index 2476a97e34..6d779c251e 100644 --- a/precompile/utils.go +++ b/precompile/utils.go @@ -17,6 +17,7 @@ var functionSignatureRegex = regexp.MustCompile(`[\w]+\(((([\w]+)?)|((([\w]+),)+ // CalculateFunctionSelector returns the 4 byte function selector that results from [functionSignature] // Ex. the function setBalance(addr address, balance uint256) should be passed in as the string: // "setBalance(address,uint256)" +// TODO: remove this after moving to ABI based function selectors. func CalculateFunctionSelector(functionSignature string) []byte { if !functionSignatureRegex.MatchString(functionSignature) { panic(fmt.Errorf("invalid function signature: %q", functionSignature)) @@ -36,16 +37,16 @@ func deductGas(suppliedGas uint64, requiredGas uint64) (uint64, error) { // packOrderedHashesWithSelector packs the function selector and ordered list of hashes into [dst] // byte slice. // assumes that [dst] has sufficient room for [functionSelector] and [hashes]. -func packOrderedHashesWithSelector(dst []byte, functionSelector []byte, hashes []common.Hash) { +func packOrderedHashesWithSelector(dst []byte, functionSelector []byte, hashes []common.Hash) error { copy(dst[:len(functionSelector)], functionSelector) - packOrderedHashes(dst[len(functionSelector):], hashes) + return packOrderedHashes(dst[len(functionSelector):], hashes) } // packOrderedHashes packs the ordered list of [hashes] into the [dst] byte buffer. // assumes that [dst] has sufficient space to pack [hashes] or else this function will panic. -func packOrderedHashes(dst []byte, hashes []common.Hash) { +func packOrderedHashes(dst []byte, hashes []common.Hash) error { if len(dst) != len(hashes)*common.HashLength { - panic(fmt.Sprintf("destination byte buffer has insufficient length (%d) for %d hashes", len(dst), len(hashes))) + return fmt.Errorf("destination byte buffer has insufficient length (%d) for %d hashes", len(dst), len(hashes)) } var ( @@ -57,6 +58,7 @@ func packOrderedHashes(dst []byte, hashes []common.Hash) { start += common.HashLength end += common.HashLength } + return nil } // returnPackedHash returns packed the byte slice with common.HashLength from [packed] From 4d011d9a0d49b4fa7310be7666677e9ce2b54e88 Mon Sep 17 00:00:00 2001 From: Ceyhun Onur Date: Wed, 21 Dec 2022 18:41:54 +0300 Subject: [PATCH 02/23] Update precompile/allow_list.go Co-authored-by: aaronbuchwald --- precompile/allow_list.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/precompile/allow_list.go b/precompile/allow_list.go index c580106db8..b4f75becdb 100644 --- a/precompile/allow_list.go +++ b/precompile/allow_list.go @@ -221,7 +221,7 @@ func createAllowListPrecompile(precompileAddr common.Address) StatefulPrecompile // Construct the contract with no fallback function. allowListFuncs := createAllowListFunctions(precompileAddr) contract, err := NewStatefulPrecompileContract(nil, allowListFuncs) - // Change this to be returned as an error after refactoring this precompile + // TODO Change this to be returned as an error after refactoring this precompile // to use the new precompile template. if err != nil { panic(err) From 2f90260717dd72aca5564fffb132b718bb1c5936 Mon Sep 17 00:00:00 2001 From: Ceyhun Onur Date: Wed, 21 Dec 2022 18:42:06 +0300 Subject: [PATCH 03/23] Update precompile/fee_config_manager.go Co-authored-by: aaronbuchwald --- precompile/fee_config_manager.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/precompile/fee_config_manager.go b/precompile/fee_config_manager.go index 97bdbfa327..4059f1f590 100644 --- a/precompile/fee_config_manager.go +++ b/precompile/fee_config_manager.go @@ -231,7 +231,7 @@ func UnpackFeeConfigInput(input []byte) (commontype.FeeConfig, error) { case blockGasCostStepKey: feeConfig.BlockGasCostStep = new(big.Int).SetBytes(packedElement) default: - // this should not ever happen. keep this as panic. + // This should never encounter an unknown fee config key panic(fmt.Sprintf("unknown fee config key: %d", i)) } } From 5991c6ea4b3b730f9a0b1066cb377877195b7c33 Mon Sep 17 00:00:00 2001 From: Ceyhun Onur Date: Wed, 21 Dec 2022 18:49:27 +0300 Subject: [PATCH 04/23] Update precompile/fee_config_manager.go Co-authored-by: aaronbuchwald --- precompile/fee_config_manager.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/precompile/fee_config_manager.go b/precompile/fee_config_manager.go index 4059f1f590..1affa533cb 100644 --- a/precompile/fee_config_manager.go +++ b/precompile/fee_config_manager.go @@ -390,7 +390,7 @@ func createFeeConfigManagerPrecompile(precompileAddr common.Address) StatefulPre feeConfigManagerFunctions = append(feeConfigManagerFunctions, setFeeConfigFunc, getFeeConfigFunc, getFeeConfigLastChangedAtFunc) // Construct the contract with no fallback function. contract, err := NewStatefulPrecompileContract(nil, feeConfigManagerFunctions) - // Change this to be returned as an error after refactoring this precompile + // TODO Change this to be returned as an error after refactoring this precompile // to use the new precompile template. if err != nil { panic(err) From 8f83fe584746a1568a92ead116523cec4d37ab35 Mon Sep 17 00:00:00 2001 From: Ceyhun Onur Date: Thu, 22 Dec 2022 12:50:00 +0300 Subject: [PATCH 05/23] fix reviews --- core/state_processor.go | 6 ++++-- miner/worker.go | 4 +++- precompile/contract.go | 3 --- precompile/fee_config_manager.go | 4 ++-- 4 files changed, 9 insertions(+), 8 deletions(-) diff --git a/core/state_processor.go b/core/state_processor.go index 6ae2bddbbf..39c99461b3 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -37,6 +37,7 @@ import ( "github.com/ava-labs/subnet-evm/params" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/log" ) // StateProcessor is a basic Processor, which takes care of transitioning @@ -79,9 +80,10 @@ func (p *StateProcessor) Process(block *types.Block, parent *types.Header, state // Configure any stateful precompiles that should go into effect during this block. err := p.config.ConfigurePrecompiles(new(big.Int).SetUint64(parent.Time), block, statedb) - // ASK: Should we panic instead? if err != nil { - return nil, nil, 0, fmt.Errorf("could not configure precompiles: %w", err) + werr := fmt.Errorf("could not configure precompiles: %w", err) + log.Error("failed to process the state changes", "err", werr) + return nil, nil, 0, err } blockContext := NewEVMBlockContext(header, p.bc, nil) diff --git a/miner/worker.go b/miner/worker.go index 976940a243..eba402601a 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -186,7 +186,9 @@ func (w *worker) commitNewWork() (*types.Block, error) { // Configure any stateful precompiles that should go into effect during this block. err = w.chainConfig.ConfigurePrecompiles(new(big.Int).SetUint64(parent.Time()), types.NewBlockWithHeader(header), env.state) if err != nil { - return nil, fmt.Errorf("failed to configure precompiles: %w", err) + werr := fmt.Errorf("failed to configure precompiles: %w", err) + log.Error("failed to commit new work", "err", werr) + return nil, werr } // Fill the block with all available pending transactions. diff --git a/precompile/contract.go b/precompile/contract.go index 9dadb02ab9..69ed968641 100644 --- a/precompile/contract.go +++ b/precompile/contract.go @@ -111,9 +111,6 @@ func NewStatefulPrecompileContract(fallback RunStatefulPrecompileFunc, functions if exists { return nil, fmt.Errorf("cannot create stateful precompile with duplicated function selector: %q", function.selector) } - if function == nil { - return nil, fmt.Errorf("cannot create stateful precompile with nil function, selector: %q", function.selector) - } contract.functions[string(function.selector)] = function } diff --git a/precompile/fee_config_manager.go b/precompile/fee_config_manager.go index 1affa533cb..de23cbde7b 100644 --- a/precompile/fee_config_manager.go +++ b/precompile/fee_config_manager.go @@ -261,7 +261,7 @@ func GetStoredFeeConfig(stateDB StateDB) commontype.FeeConfig { case blockGasCostStepKey: feeConfig.BlockGasCostStep = new(big.Int).Set(val.Big()) default: - // this should not ever happen. keep this as panic. + // This should never encounter an unknown fee config key panic(fmt.Sprintf("unknown fee config key: %d", i)) } } @@ -300,7 +300,7 @@ func StoreFeeConfig(stateDB StateDB, feeConfig commontype.FeeConfig, blockContex case blockGasCostStepKey: input = common.BigToHash(feeConfig.BlockGasCostStep) default: - // this should not ever happen. keep this as panic. + // this should not ever happen. panic(fmt.Sprintf("unknown fee config key: %d", i)) } stateDB.SetState(FeeConfigManagerAddress, common.Hash{byte(i)}, input) From ccc78106aea0d0c511ddd624d0c9707675ecde88 Mon Sep 17 00:00:00 2001 From: Ceyhun Onur Date: Fri, 23 Dec 2022 16:02:17 +0300 Subject: [PATCH 06/23] wrap errors in ConfigurePrecompiles --- core/state_processor.go | 3 +-- miner/worker.go | 5 ++--- params/precompile_config.go | 2 +- precompile/fee_config_manager.go | 2 +- 4 files changed, 5 insertions(+), 7 deletions(-) diff --git a/core/state_processor.go b/core/state_processor.go index 39c99461b3..6f6454fd0b 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -81,8 +81,7 @@ func (p *StateProcessor) Process(block *types.Block, parent *types.Header, state // Configure any stateful precompiles that should go into effect during this block. err := p.config.ConfigurePrecompiles(new(big.Int).SetUint64(parent.Time), block, statedb) if err != nil { - werr := fmt.Errorf("could not configure precompiles: %w", err) - log.Error("failed to process the state changes", "err", werr) + log.Error("failed to process the state changes", "err", err) return nil, nil, 0, err } diff --git a/miner/worker.go b/miner/worker.go index eba402601a..7eb6c8ae69 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -186,9 +186,8 @@ func (w *worker) commitNewWork() (*types.Block, error) { // Configure any stateful precompiles that should go into effect during this block. err = w.chainConfig.ConfigurePrecompiles(new(big.Int).SetUint64(parent.Time()), types.NewBlockWithHeader(header), env.state) if err != nil { - werr := fmt.Errorf("failed to configure precompiles: %w", err) - log.Error("failed to commit new work", "err", werr) - return nil, werr + log.Error("failed to commit new work", "err", err) + return nil, err } // Fill the block with all available pending transactions. diff --git a/params/precompile_config.go b/params/precompile_config.go index f58ac8fa84..cd629ced55 100644 --- a/params/precompile_config.go +++ b/params/precompile_config.go @@ -286,7 +286,7 @@ func (c *ChainConfig) ConfigurePrecompiles(parentTimestamp *big.Int, blockContex } else { log.Info("Activating new precompile", "precompileAddress", address, "config", config) if err := precompile.Configure(c, blockContext, config, statedb); err != nil { - return err + return fmt.Errorf("could not configure precompile, precompileAddress: %s, reason: %w", address, err) } } } diff --git a/precompile/fee_config_manager.go b/precompile/fee_config_manager.go index de23cbde7b..471e7ca68a 100644 --- a/precompile/fee_config_manager.go +++ b/precompile/fee_config_manager.go @@ -300,7 +300,7 @@ func StoreFeeConfig(stateDB StateDB, feeConfig commontype.FeeConfig, blockContex case blockGasCostStepKey: input = common.BigToHash(feeConfig.BlockGasCostStep) default: - // this should not ever happen. + // This should never encounter an unknown fee config key panic(fmt.Sprintf("unknown fee config key: %d", i)) } stateDB.SetState(FeeConfigManagerAddress, common.Hash{byte(i)}, input) From 93296c659fd768aafc9dadec809b40d2f35de8cd Mon Sep 17 00:00:00 2001 From: Ceyhun Onur Date: Fri, 23 Dec 2022 16:06:45 +0300 Subject: [PATCH 07/23] cleaner errors --- precompile/fee_config_manager.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/precompile/fee_config_manager.go b/precompile/fee_config_manager.go index 471e7ca68a..56567d840a 100644 --- a/precompile/fee_config_manager.go +++ b/precompile/fee_config_manager.go @@ -114,12 +114,12 @@ func (c *FeeConfigManagerConfig) Configure(chainConfig ChainConfig, state StateD if c.InitialFeeConfig != nil { if err := StoreFeeConfig(state, *c.InitialFeeConfig, blockContext); err != nil { // This should not happen since we already checked this config with Verify() - return fmt.Errorf("invalid feeConfig provided: %w", err) + return fmt.Errorf("cannot configure given initial fee config: %w", err) } } else { if err := StoreFeeConfig(state, chainConfig.GetFeeConfig(), blockContext); err != nil { // This should not happen since we already checked the chain config in the genesis creation. - return fmt.Errorf("invalid feeConfig provided in chainConfig: %w", err) + return fmt.Errorf("cannot configure fee config in chain config: %w", err) } } return c.AllowListConfig.Configure(state, FeeConfigManagerAddress) @@ -277,7 +277,7 @@ func GetFeeConfigLastChangedAt(stateDB StateDB) *big.Int { // A validation on [feeConfig] is done before storing. func StoreFeeConfig(stateDB StateDB, feeConfig commontype.FeeConfig, blockContext BlockContext) error { if err := feeConfig.Verify(); err != nil { - return err + return fmt.Errorf("cannot verify fee config: %w", err) } for i := minFeeConfigFieldKey; i <= numFeeConfigField; i++ { From 50bad393ccf43ab69430f836d851826e7cc4133a Mon Sep 17 00:00:00 2001 From: Ceyhun Onur Date: Fri, 23 Dec 2022 17:10:26 +0300 Subject: [PATCH 08/23] move reward manager precompile to package (WIP) --- accounts/abi/bind/precompile_template.go | 18 +- precompile/allow_list.go | 40 ++-- precompile/config_test.go | 72 ------ precompile/contract.go | 16 +- precompile/contract_deployer_allow_list.go | 4 +- precompile/contract_native_minter.go | 12 +- precompile/fee_config_manager.go | 26 +-- precompile/params.go | 4 +- .../config.go} | 220 ++++-------------- precompile/rewardmanager/config_test.go | 121 ++++++++++ .../contract.abi} | 0 precompile/rewardmanager/contract.go | 150 ++++++++++++ precompile/tx_allow_list.go | 4 +- precompile/utils.go | 4 +- 14 files changed, 377 insertions(+), 314 deletions(-) rename precompile/{reward_manager.go => rewardmanager/config.go} (52%) create mode 100644 precompile/rewardmanager/config_test.go rename precompile/{reward_manager.abi => rewardmanager/contract.abi} (100%) create mode 100644 precompile/rewardmanager/contract.go diff --git a/accounts/abi/bind/precompile_template.go b/accounts/abi/bind/precompile_template.go index 596d96c351..6184925a81 100644 --- a/accounts/abi/bind/precompile_template.go +++ b/accounts/abi/bind/precompile_template.go @@ -231,7 +231,7 @@ func (c *{{.Contract.Type}}Config) Verify() error { {{if .Contract.AllowList}} // Get{{.Contract.Type}}AllowListStatus returns the role of [address] for the {{.Contract.Type}} list. func Get{{.Contract.Type}}AllowListStatus(stateDB StateDB, address common.Address) AllowListRole { - return getAllowListStatus(stateDB, {{.Contract.Type}}Address, address) + return GetAllowListStatus(stateDB, {{.Contract.Type}}Address, address) } // Set{{.Contract.Type}}AllowListStatus sets the permissions of [address] to [role] for the @@ -241,7 +241,7 @@ func Get{{.Contract.Type}}AllowListStatus(stateDB StateDB, address common.Addres // conflicts with the same slot [role] is stored. // Precompile implementations must use a different key than [address] for their storage. func Set{{.Contract.Type}}AllowListStatus(stateDB StateDB, address common.Address, role AllowListRole) { - setAllowListRole(stateDB, {{.Contract.Type}}Address, address, role) + SetAllowListRole(stateDB, {{.Contract.Type}}Address, address, role) } {{end}} @@ -310,7 +310,7 @@ func Pack{{$method.Normalized.Name}}Output ({{decapitalise $output.Name}} {{bind {{end}} func {{decapitalise .Normalized.Name}}(accessibleState PrecompileAccessibleState, caller common.Address, addr common.Address, input []byte, suppliedGas uint64, readOnly bool) (ret []byte, remainingGas uint64, err error) { - if remainingGas, err = deductGas(suppliedGas, {{.Normalized.Name}}GasCost); err != nil { + if remainingGas, err = DeductGas(suppliedGas, {{.Normalized.Name}}GasCost); err != nil { return nil, 0, err } @@ -338,7 +338,7 @@ func {{decapitalise .Normalized.Name}}(accessibleState PrecompileAccessibleState // You can modify/delete this code if you don't want this function to be restricted by the allow list. stateDB := accessibleState.GetStateDB() // Verify that the caller is in the allow list and therefore has the right to modify it - callerStatus := getAllowListStatus(stateDB, {{$contract.Type}}Address, caller) + callerStatus := GetAllowListStatus(stateDB, {{$contract.Type}}Address, caller) if !callerStatus.IsEnabled() { return nil, remainingGas, fmt.Errorf("%w: %s", ErrCannot{{.Normalized.Name}}, caller) } @@ -375,7 +375,7 @@ func {{decapitalise .Normalized.Name}}(accessibleState PrecompileAccessibleState // {{decapitalise $contract.Type}}Fallback executed if a function identifier does not match any of the available functions in a smart contract. // This function cannot take an input or return an output. func {{decapitalise $contract.Type}}Fallback (accessibleState PrecompileAccessibleState, caller common.Address, addr common.Address, _ []byte, suppliedGas uint64, readOnly bool) (ret []byte, remainingGas uint64, err error) { - if remainingGas, err = deductGas(suppliedGas, {{$contract.Type}}FallbackGasCost); err != nil { + if remainingGas, err = DeductGas(suppliedGas, {{$contract.Type}}FallbackGasCost); err != nil { return nil, 0, err } @@ -389,7 +389,7 @@ func {{decapitalise $contract.Type}}Fallback (accessibleState PrecompileAccessib // You can modify/delete this code if you don't want this function to be restricted by the allow list. stateDB := accessibleState.GetStateDB() // Verify that the caller is in the allow list and therefore has the right to modify it - callerStatus := getAllowListStatus(stateDB, {{$contract.Type}}Address, caller) + callerStatus := GetAllowListStatus(stateDB, {{$contract.Type}}Address, caller) if !callerStatus.IsEnabled() { return nil, remainingGas, fmt.Errorf("%w: %s", Err{{$contract.Type}}CannotFallback, caller) } @@ -411,9 +411,9 @@ func {{decapitalise $contract.Type}}Fallback (accessibleState PrecompileAccessib // create{{.Contract.Type}}Precompile returns a StatefulPrecompiledContract with getters and setters for the precompile. {{if .Contract.AllowList}} // Access to the getters/setters is controlled by an allow list for [precompileAddr].{{end}} func create{{.Contract.Type}}Precompile(precompileAddr common.Address) (StatefulPrecompiledContract, error) { - var functions []*statefulPrecompileFunction + var functions []*StatefulPrecompileFunction {{- if .Contract.AllowList}} - functions = append(functions, createAllowListFunctions(precompileAddr)...) + functions = append(functions, CreateAllowListFunctions(precompileAddr)...) {{- end}} abiFunctionMap := map[string]RunStatefulPrecompileFunc{ @@ -427,7 +427,7 @@ func create{{.Contract.Type}}Precompile(precompileAddr common.Address) (Stateful if !ok { return nil, fmt.Errorf("given method (%s) does not exist in the ABI", name) } - functions = append(functions, newStatefulPrecompileFunction(method.ID, function)) + functions = append(functions, NewStatefulPrecompileFunction(method.ID, function)) } {{- if .Contract.Fallback}} diff --git a/precompile/allow_list.go b/precompile/allow_list.go index b4f75becdb..a22b9f110c 100644 --- a/precompile/allow_list.go +++ b/precompile/allow_list.go @@ -18,8 +18,8 @@ const ( SetNoneFuncKey = "setNone" ReadAllowListFuncKey = "readAllowList" - ModifyAllowListGasCost = writeGasCostPerSlot - ReadAllowListGasCost = readGasCostPerSlot + ModifyAllowListGasCost = WriteGasCostPerSlot + ReadAllowListGasCost = ReadGasCostPerSlot ) var ( @@ -48,10 +48,10 @@ type AllowListConfig struct { // the addresses in [AllowListAdmins]. func (c *AllowListConfig) Configure(state StateDB, precompileAddr common.Address) error { for _, enabledAddr := range c.EnabledAddresses { - setAllowListRole(state, precompileAddr, enabledAddr, AllowListEnabled) + SetAllowListRole(state, precompileAddr, enabledAddr, AllowListEnabled) } for _, adminAddr := range c.AllowListAdmins { - setAllowListRole(state, precompileAddr, adminAddr, AllowListAdmin) + SetAllowListRole(state, precompileAddr, adminAddr, AllowListAdmin) } return nil } @@ -112,18 +112,18 @@ func (c *AllowListConfig) Verify() error { return nil } -// getAllowListStatus returns the allow list role of [address] for the precompile +// GetAllowListStatus returns the allow list role of [address] for the precompile // at [precompileAddr] -func getAllowListStatus(state StateDB, precompileAddr common.Address, address common.Address) AllowListRole { +func GetAllowListStatus(state StateDB, precompileAddr common.Address, address common.Address) AllowListRole { // Generate the state key for [address] addressKey := address.Hash() return AllowListRole(state.GetState(precompileAddr, addressKey)) } -// setAllowListRole sets the permissions of [address] to [role] for the precompile +// SetAllowListRole sets the permissions of [address] to [role] for the precompile // at [precompileAddr]. // assumes [role] has already been verified as valid. -func setAllowListRole(stateDB StateDB, precompileAddr, address common.Address, role AllowListRole) { +func SetAllowListRole(stateDB StateDB, precompileAddr, address common.Address, role AllowListRole) { // Generate the state key for [address] addressKey := address.Hash() // Assign [role] to the address @@ -168,7 +168,7 @@ func PackReadAllowList(address common.Address) []byte { // This execution function is speciifc to [precompileAddr]. func createAllowListRoleSetter(precompileAddr common.Address, role AllowListRole) RunStatefulPrecompileFunc { return func(evm PrecompileAccessibleState, callerAddr, addr common.Address, input []byte, suppliedGas uint64, readOnly bool) (ret []byte, remainingGas uint64, err error) { - if remainingGas, err = deductGas(suppliedGas, ModifyAllowListGasCost); err != nil { + if remainingGas, err = DeductGas(suppliedGas, ModifyAllowListGasCost); err != nil { return nil, 0, err } @@ -185,12 +185,12 @@ func createAllowListRoleSetter(precompileAddr common.Address, role AllowListRole stateDB := evm.GetStateDB() // Verify that the caller is in the allow list and therefore has the right to modify it - callerStatus := getAllowListStatus(stateDB, precompileAddr, callerAddr) + callerStatus := GetAllowListStatus(stateDB, precompileAddr, callerAddr) if !callerStatus.IsAdmin() { return nil, remainingGas, fmt.Errorf("%w: %s", ErrCannotModifyAllowList, callerAddr) } - setAllowListRole(stateDB, precompileAddr, modifyAddress, role) + SetAllowListRole(stateDB, precompileAddr, modifyAddress, role) // Return an empty output and the remaining gas return []byte{}, remainingGas, nil } @@ -201,7 +201,7 @@ func createAllowListRoleSetter(precompileAddr common.Address, role AllowListRole // designated role of that address func createReadAllowList(precompileAddr common.Address) RunStatefulPrecompileFunc { return func(evm PrecompileAccessibleState, callerAddr common.Address, addr common.Address, input []byte, suppliedGas uint64, readOnly bool) (ret []byte, remainingGas uint64, err error) { - if remainingGas, err = deductGas(suppliedGas, ReadAllowListGasCost); err != nil { + if remainingGas, err = DeductGas(suppliedGas, ReadAllowListGasCost); err != nil { return nil, 0, err } @@ -210,7 +210,7 @@ func createReadAllowList(precompileAddr common.Address) RunStatefulPrecompileFun } readAddress := common.BytesToAddress(input) - role := getAllowListStatus(evm.GetStateDB(), precompileAddr, readAddress) + role := GetAllowListStatus(evm.GetStateDB(), precompileAddr, readAddress) roleBytes := common.Hash(role).Bytes() return roleBytes, remainingGas, nil } @@ -219,7 +219,7 @@ func createReadAllowList(precompileAddr common.Address) RunStatefulPrecompileFun // createAllowListPrecompile returns a StatefulPrecompiledContract with R/W control of an allow list at [precompileAddr] func createAllowListPrecompile(precompileAddr common.Address) StatefulPrecompiledContract { // Construct the contract with no fallback function. - allowListFuncs := createAllowListFunctions(precompileAddr) + allowListFuncs := CreateAllowListFunctions(precompileAddr) contract, err := NewStatefulPrecompileContract(nil, allowListFuncs) // TODO Change this to be returned as an error after refactoring this precompile // to use the new precompile template. @@ -229,11 +229,11 @@ func createAllowListPrecompile(precompileAddr common.Address) StatefulPrecompile return contract } -func createAllowListFunctions(precompileAddr common.Address) []*statefulPrecompileFunction { - setAdmin := newStatefulPrecompileFunction(setAdminSignature, createAllowListRoleSetter(precompileAddr, AllowListAdmin)) - setEnabled := newStatefulPrecompileFunction(setEnabledSignature, createAllowListRoleSetter(precompileAddr, AllowListEnabled)) - setNone := newStatefulPrecompileFunction(setNoneSignature, createAllowListRoleSetter(precompileAddr, AllowListNoRole)) - read := newStatefulPrecompileFunction(readAllowListSignature, createReadAllowList(precompileAddr)) +func CreateAllowListFunctions(precompileAddr common.Address) []*StatefulPrecompileFunction { + setAdmin := NewStatefulPrecompileFunction(setAdminSignature, createAllowListRoleSetter(precompileAddr, AllowListAdmin)) + setEnabled := NewStatefulPrecompileFunction(setEnabledSignature, createAllowListRoleSetter(precompileAddr, AllowListEnabled)) + setNone := NewStatefulPrecompileFunction(setNoneSignature, createAllowListRoleSetter(precompileAddr, AllowListNoRole)) + read := NewStatefulPrecompileFunction(readAllowListSignature, createReadAllowList(precompileAddr)) - return []*statefulPrecompileFunction{setAdmin, setEnabled, setNone, read} + return []*StatefulPrecompileFunction{setAdmin, setEnabled, setNone, read} } diff --git a/precompile/config_test.go b/precompile/config_test.go index a396cec543..67ed5dbf85 100644 --- a/precompile/config_test.go +++ b/precompile/config_test.go @@ -388,75 +388,3 @@ func TestEqualFeeConfigManagerConfig(t *testing.T) { }) } } - -func TestEqualRewardManagerConfig(t *testing.T) { - admins := []common.Address{{1}} - enableds := []common.Address{{2}} - tests := []struct { - name string - config StatefulPrecompileConfig - other StatefulPrecompileConfig - expected bool - }{ - { - name: "non-nil config and nil other", - config: NewRewardManagerConfig(big.NewInt(3), admins, enableds, nil), - other: nil, - expected: false, - }, - { - name: "different type", - config: NewRewardManagerConfig(big.NewInt(3), admins, enableds, nil), - other: NewTxAllowListConfig(big.NewInt(3), []common.Address{{1}}, []common.Address{{2}}), - expected: false, - }, - { - name: "different timestamp", - config: NewRewardManagerConfig(big.NewInt(3), admins, nil, nil), - other: NewRewardManagerConfig(big.NewInt(4), admins, nil, nil), - expected: false, - }, - { - name: "different enabled", - config: NewRewardManagerConfig(big.NewInt(3), admins, nil, nil), - other: NewRewardManagerConfig(big.NewInt(3), admins, enableds, nil), - expected: false, - }, - { - name: "non-nil initial config and nil initial config", - config: NewRewardManagerConfig(big.NewInt(3), admins, nil, &InitialRewardConfig{ - AllowFeeRecipients: true, - }), - other: NewRewardManagerConfig(big.NewInt(3), admins, nil, nil), - expected: false, - }, - { - name: "different initial config", - config: NewRewardManagerConfig(big.NewInt(3), admins, nil, &InitialRewardConfig{ - RewardAddress: common.HexToAddress("0x01"), - }), - other: NewRewardManagerConfig(big.NewInt(3), admins, nil, - &InitialRewardConfig{ - RewardAddress: common.HexToAddress("0x02"), - }), - expected: false, - }, - { - name: "same config", - config: NewRewardManagerConfig(big.NewInt(3), admins, nil, &InitialRewardConfig{ - RewardAddress: common.HexToAddress("0x01"), - }), - other: NewRewardManagerConfig(big.NewInt(3), admins, nil, &InitialRewardConfig{ - RewardAddress: common.HexToAddress("0x01"), - }), - expected: true, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - require := require.New(t) - - require.Equal(tt.expected, tt.config.Equal(tt.other)) - }) - } -} diff --git a/precompile/contract.go b/precompile/contract.go index 69ed968641..ca12252ab0 100644 --- a/precompile/contract.go +++ b/precompile/contract.go @@ -73,8 +73,8 @@ type StatefulPrecompiledContract interface { Run(accessibleState PrecompileAccessibleState, caller common.Address, addr common.Address, input []byte, suppliedGas uint64, readOnly bool) (ret []byte, remainingGas uint64, err error) } -// statefulPrecompileFunction defines a function implemented by a stateful precompile -type statefulPrecompileFunction struct { +// StatefulPrecompileFunction defines a function implemented by a stateful precompile +type StatefulPrecompileFunction struct { // selector is the 4 byte function selector for this function // This should be calculated from the function signature using CalculateFunctionSelector selector []byte @@ -82,9 +82,9 @@ type statefulPrecompileFunction struct { execute RunStatefulPrecompileFunc } -// newStatefulPrecompileFunction creates a stateful precompile function with the given arguments -func newStatefulPrecompileFunction(selector []byte, execute RunStatefulPrecompileFunc) *statefulPrecompileFunction { - return &statefulPrecompileFunction{ +// NewStatefulPrecompileFunction creates a stateful precompile function with the given arguments +func NewStatefulPrecompileFunction(selector []byte, execute RunStatefulPrecompileFunc) *StatefulPrecompileFunction { + return &StatefulPrecompileFunction{ selector: selector, execute: execute, } @@ -95,16 +95,16 @@ func newStatefulPrecompileFunction(selector []byte, execute RunStatefulPrecompil // Note: because we only ever read from [functions] there no lock is required to make it thread-safe. type statefulPrecompileWithFunctionSelectors struct { fallback RunStatefulPrecompileFunc - functions map[string]*statefulPrecompileFunction + functions map[string]*StatefulPrecompileFunction } // NewStatefulPrecompileContract generates new StatefulPrecompile using [functions] as the available functions and [fallback] // as an optional fallback if there is no input data. Note: the selector of [fallback] will be ignored, so it is required to be left empty. -func NewStatefulPrecompileContract(fallback RunStatefulPrecompileFunc, functions []*statefulPrecompileFunction) (StatefulPrecompiledContract, error) { +func NewStatefulPrecompileContract(fallback RunStatefulPrecompileFunc, functions []*StatefulPrecompileFunction) (StatefulPrecompiledContract, error) { // Construct the contract and populate [functions]. contract := &statefulPrecompileWithFunctionSelectors{ fallback: fallback, - functions: make(map[string]*statefulPrecompileFunction), + functions: make(map[string]*StatefulPrecompileFunction), } for _, function := range functions { _, exists := contract.functions[string(function.selector)] diff --git a/precompile/contract_deployer_allow_list.go b/precompile/contract_deployer_allow_list.go index 11df6ff3fe..8b266f2768 100644 --- a/precompile/contract_deployer_allow_list.go +++ b/precompile/contract_deployer_allow_list.go @@ -80,12 +80,12 @@ func (c *ContractDeployerAllowListConfig) String() string { // GetContractDeployerAllowListStatus returns the role of [address] for the contract deployer // allow list. func GetContractDeployerAllowListStatus(stateDB StateDB, address common.Address) AllowListRole { - return getAllowListStatus(stateDB, ContractDeployerAllowListAddress, address) + return GetAllowListStatus(stateDB, ContractDeployerAllowListAddress, address) } // SetContractDeployerAllowListStatus sets the permissions of [address] to [role] for the // contract deployer allow list. // assumes [role] has already been verified as valid. func SetContractDeployerAllowListStatus(stateDB StateDB, address common.Address, role AllowListRole) { - setAllowListRole(stateDB, ContractDeployerAllowListAddress, address, role) + SetAllowListRole(stateDB, ContractDeployerAllowListAddress, address, role) } diff --git a/precompile/contract_native_minter.go b/precompile/contract_native_minter.go index 26ccaf8e68..92080157e2 100644 --- a/precompile/contract_native_minter.go +++ b/precompile/contract_native_minter.go @@ -143,13 +143,13 @@ func (c *ContractNativeMinterConfig) String() string { // GetContractNativeMinterStatus returns the role of [address] for the minter list. func GetContractNativeMinterStatus(stateDB StateDB, address common.Address) AllowListRole { - return getAllowListStatus(stateDB, ContractNativeMinterAddress, address) + return GetAllowListStatus(stateDB, ContractNativeMinterAddress, address) } // SetContractNativeMinterStatus sets the permissions of [address] to [role] for the // minter list. assumes [role] has already been verified as valid. func SetContractNativeMinterStatus(stateDB StateDB, address common.Address, role AllowListRole) { - setAllowListRole(stateDB, ContractNativeMinterAddress, address, role) + SetAllowListRole(stateDB, ContractNativeMinterAddress, address, role) } // PackMintInput packs [address] and [amount] into the appropriate arguments for minting operation. @@ -179,7 +179,7 @@ func UnpackMintInput(input []byte) (common.Address, *big.Int, error) { // mintNativeCoin checks if the caller is permissioned for minting operation. // The execution function parses the [input] into native coin amount and receiver address. func mintNativeCoin(accessibleState PrecompileAccessibleState, caller common.Address, addr common.Address, input []byte, suppliedGas uint64, readOnly bool) (ret []byte, remainingGas uint64, err error) { - if remainingGas, err = deductGas(suppliedGas, MintGasCost); err != nil { + if remainingGas, err = DeductGas(suppliedGas, MintGasCost); err != nil { return nil, 0, err } @@ -194,7 +194,7 @@ func mintNativeCoin(accessibleState PrecompileAccessibleState, caller common.Add stateDB := accessibleState.GetStateDB() // Verify that the caller is in the allow list and therefore has the right to modify it - callerStatus := getAllowListStatus(stateDB, ContractNativeMinterAddress, caller) + callerStatus := GetAllowListStatus(stateDB, ContractNativeMinterAddress, caller) if !callerStatus.IsEnabled() { return nil, remainingGas, fmt.Errorf("%w: %s", ErrCannotMint, caller) } @@ -211,9 +211,9 @@ func mintNativeCoin(accessibleState PrecompileAccessibleState, caller common.Add // createNativeMinterPrecompile returns a StatefulPrecompiledContract with R/W control of an allow list at [precompileAddr] and a native coin minter. func createNativeMinterPrecompile(precompileAddr common.Address) StatefulPrecompiledContract { - enabledFuncs := createAllowListFunctions(precompileAddr) + enabledFuncs := CreateAllowListFunctions(precompileAddr) - mintFunc := newStatefulPrecompileFunction(mintSignature, mintNativeCoin) + mintFunc := NewStatefulPrecompileFunction(mintSignature, mintNativeCoin) enabledFuncs = append(enabledFuncs, mintFunc) // Construct the contract with no fallback function. diff --git a/precompile/fee_config_manager.go b/precompile/fee_config_manager.go index 56567d840a..1cad22cb8e 100644 --- a/precompile/fee_config_manager.go +++ b/precompile/fee_config_manager.go @@ -32,9 +32,9 @@ const ( // [numFeeConfigField] fields in FeeConfig struct feeConfigInputLen = common.HashLength * numFeeConfigField - SetFeeConfigGasCost = writeGasCostPerSlot * (numFeeConfigField + 1) // plus one for setting last changed at - GetFeeConfigGasCost = readGasCostPerSlot * numFeeConfigField - GetLastChangedAtGasCost = readGasCostPerSlot + SetFeeConfigGasCost = WriteGasCostPerSlot * (numFeeConfigField + 1) // plus one for setting last changed at + GetFeeConfigGasCost = ReadGasCostPerSlot * numFeeConfigField + GetLastChangedAtGasCost = ReadGasCostPerSlot ) var ( @@ -149,13 +149,13 @@ func (c *FeeConfigManagerConfig) String() string { // GetFeeConfigManagerStatus returns the role of [address] for the fee config manager list. func GetFeeConfigManagerStatus(stateDB StateDB, address common.Address) AllowListRole { - return getAllowListStatus(stateDB, FeeConfigManagerAddress, address) + return GetAllowListStatus(stateDB, FeeConfigManagerAddress, address) } // SetFeeConfigManagerStatus sets the permissions of [address] to [role] for the // fee config manager list. assumes [role] has already been verified as valid. func SetFeeConfigManagerStatus(stateDB StateDB, address common.Address, role AllowListRole) { - setAllowListRole(stateDB, FeeConfigManagerAddress, address, role) + SetAllowListRole(stateDB, FeeConfigManagerAddress, address, role) } // PackGetFeeConfigInput packs the getFeeConfig signature @@ -318,7 +318,7 @@ func StoreFeeConfig(stateDB StateDB, feeConfig commontype.FeeConfig, blockContex // setFeeConfig checks if the caller has permissions to set the fee config. // The execution function parses [input] into FeeConfig structure and sets contract storage accordingly. func setFeeConfig(accessibleState PrecompileAccessibleState, caller common.Address, addr common.Address, input []byte, suppliedGas uint64, readOnly bool) (ret []byte, remainingGas uint64, err error) { - if remainingGas, err = deductGas(suppliedGas, SetFeeConfigGasCost); err != nil { + if remainingGas, err = DeductGas(suppliedGas, SetFeeConfigGasCost); err != nil { return nil, 0, err } @@ -333,7 +333,7 @@ func setFeeConfig(accessibleState PrecompileAccessibleState, caller common.Addre stateDB := accessibleState.GetStateDB() // Verify that the caller is in the allow list and therefore has the right to modify it - callerStatus := getAllowListStatus(stateDB, FeeConfigManagerAddress, caller) + callerStatus := GetAllowListStatus(stateDB, FeeConfigManagerAddress, caller) if !callerStatus.IsEnabled() { return nil, remainingGas, fmt.Errorf("%w: %s", ErrCannotChangeFee, caller) } @@ -349,7 +349,7 @@ func setFeeConfig(accessibleState PrecompileAccessibleState, caller common.Addre // getFeeConfig returns the stored fee config as an output. // The execution function reads the contract state for the stored fee config and returns the output. func getFeeConfig(accessibleState PrecompileAccessibleState, caller common.Address, addr common.Address, input []byte, suppliedGas uint64, readOnly bool) (ret []byte, remainingGas uint64, err error) { - if remainingGas, err = deductGas(suppliedGas, GetFeeConfigGasCost); err != nil { + if remainingGas, err = DeductGas(suppliedGas, GetFeeConfigGasCost); err != nil { return nil, 0, err } @@ -367,7 +367,7 @@ func getFeeConfig(accessibleState PrecompileAccessibleState, caller common.Addre // getFeeConfigLastChangedAt returns the block number that fee config was last changed in. // The execution function reads the contract state for the stored block number and returns the output. func getFeeConfigLastChangedAt(accessibleState PrecompileAccessibleState, caller common.Address, addr common.Address, input []byte, suppliedGas uint64, readOnly bool) (ret []byte, remainingGas uint64, err error) { - if remainingGas, err = deductGas(suppliedGas, GetLastChangedAtGasCost); err != nil { + if remainingGas, err = DeductGas(suppliedGas, GetLastChangedAtGasCost); err != nil { return nil, 0, err } @@ -381,11 +381,11 @@ func getFeeConfigLastChangedAt(accessibleState PrecompileAccessibleState, caller // with getters and setters for the chain's fee config. Access to the getters/setters // is controlled by an allow list for [precompileAddr]. func createFeeConfigManagerPrecompile(precompileAddr common.Address) StatefulPrecompiledContract { - feeConfigManagerFunctions := createAllowListFunctions(precompileAddr) + feeConfigManagerFunctions := CreateAllowListFunctions(precompileAddr) - setFeeConfigFunc := newStatefulPrecompileFunction(setFeeConfigSignature, setFeeConfig) - getFeeConfigFunc := newStatefulPrecompileFunction(getFeeConfigSignature, getFeeConfig) - getFeeConfigLastChangedAtFunc := newStatefulPrecompileFunction(getFeeConfigLastChangedAtSignature, getFeeConfigLastChangedAt) + setFeeConfigFunc := NewStatefulPrecompileFunction(setFeeConfigSignature, setFeeConfig) + getFeeConfigFunc := NewStatefulPrecompileFunction(getFeeConfigSignature, getFeeConfig) + getFeeConfigLastChangedAtFunc := NewStatefulPrecompileFunction(getFeeConfigLastChangedAtSignature, getFeeConfigLastChangedAt) feeConfigManagerFunctions = append(feeConfigManagerFunctions, setFeeConfigFunc, getFeeConfigFunc, getFeeConfigLastChangedAtFunc) // Construct the contract with no fallback function. diff --git a/precompile/params.go b/precompile/params.go index 965ab1df20..294ab328fa 100644 --- a/precompile/params.go +++ b/precompile/params.go @@ -11,8 +11,8 @@ import ( // Gas costs for stateful precompiles const ( - writeGasCostPerSlot = 20_000 - readGasCostPerSlot = 5_000 + WriteGasCostPerSlot = 20_000 + ReadGasCostPerSlot = 5_000 ) // Designated addresses of stateful precompiles diff --git a/precompile/reward_manager.go b/precompile/rewardmanager/config.go similarity index 52% rename from precompile/reward_manager.go rename to precompile/rewardmanager/config.go index 7262efa0b8..5287b16b2b 100644 --- a/precompile/reward_manager.go +++ b/precompile/rewardmanager/config.go @@ -4,17 +4,16 @@ // Code generated // This file is a generated precompile contract with stubbed abstract functions. -package precompile +package rewardmanager import ( - "encoding/json" "errors" "fmt" - "math/big" "strings" "github.com/ava-labs/subnet-evm/accounts/abi" "github.com/ava-labs/subnet-evm/constants" + "github.com/ava-labs/subnet-evm/precompile" "github.com/ava-labs/subnet-evm/vmerrs" _ "embed" @@ -23,16 +22,16 @@ import ( ) const ( - AllowFeeRecipientsGasCost uint64 = (writeGasCostPerSlot) + ReadAllowListGasCost // write 1 slot + read allow list - AreFeeRecipientsAllowedGasCost uint64 = readGasCostPerSlot - CurrentRewardAddressGasCost uint64 = readGasCostPerSlot - DisableRewardsGasCost uint64 = (writeGasCostPerSlot) + ReadAllowListGasCost // write 1 slot + read allow list - SetRewardAddressGasCost uint64 = (writeGasCostPerSlot) + ReadAllowListGasCost // write 1 slot + read allow list + AllowFeeRecipientsGasCost uint64 = (precompile.WriteGasCostPerSlot) + precompile.ReadAllowListGasCost // write 1 slot + read allow list + AreFeeRecipientsAllowedGasCost uint64 = precompile.ReadAllowListGasCost + CurrentRewardAddressGasCost uint64 = precompile.ReadAllowListGasCost + DisableRewardsGasCost uint64 = (precompile.WriteGasCostPerSlot) + precompile.ReadAllowListGasCost // write 1 slot + read allow list + SetRewardAddressGasCost uint64 = (precompile.WriteGasCostPerSlot) + precompile.ReadAllowListGasCost // write 1 slot + read allow list ) // Singleton StatefulPrecompiledContract and signatures. var ( - _ StatefulPrecompileConfig = &RewardManagerConfig{} + _ precompile.StatefulPrecompileConfig = &RewardManagerConfig{} ErrCannotAllowFeeRecipients = errors.New("non-enabled cannot call allowFeeRecipients") ErrCannotAreFeeRecipientsAllowed = errors.New("non-enabled cannot call areFeeRecipientsAllowed") @@ -47,169 +46,34 @@ var ( //go:embed reward_manager.abi RewardManagerRawABI string - RewardManagerABI abi.ABI // will be initialized by init function - RewardManagerPrecompile StatefulPrecompiledContract // will be initialized by init function + RewardManagerABI abi.ABI // will be initialized by init function + RewardManagerPrecompile precompile.StatefulPrecompiledContract // will be initialized by init function rewardAddressStorageKey = common.Hash{'r', 'a', 's', 'k'} allowFeeRecipientsAddressValue = common.Hash{'a', 'f', 'r', 'a', 'v'} ) -type InitialRewardConfig struct { - AllowFeeRecipients bool `json:"allowFeeRecipients"` - RewardAddress common.Address `json:"rewardAddress,omitempty"` -} - -func (i *InitialRewardConfig) Verify() error { - switch { - case i.AllowFeeRecipients && i.RewardAddress != (common.Address{}): - return ErrCannotEnableBothRewards - default: - return nil - } -} - -func (c *InitialRewardConfig) Equal(other *InitialRewardConfig) bool { - if other == nil { - return false - } - - return c.AllowFeeRecipients == other.AllowFeeRecipients && c.RewardAddress == other.RewardAddress -} - -func (i *InitialRewardConfig) Configure(state StateDB) error { - // enable allow fee recipients - if i.AllowFeeRecipients { - EnableAllowFeeRecipients(state) - } else if i.RewardAddress == (common.Address{}) { - // if reward address is empty and allow fee recipients is false - // then disable rewards - DisableFeeRewards(state) - } else { - // set reward address - return StoreRewardAddress(state, i.RewardAddress) - } - return nil -} - -// RewardManagerConfig implements the StatefulPrecompileConfig -// interface while adding in the RewardManager specific precompile config. -type RewardManagerConfig struct { - AllowListConfig - UpgradeableConfig - InitialRewardConfig *InitialRewardConfig `json:"initialRewardConfig,omitempty"` -} - func init() { parsed, err := abi.JSON(strings.NewReader(RewardManagerRawABI)) if err != nil { panic(err) } RewardManagerABI = parsed - RewardManagerPrecompile, err = createRewardManagerPrecompile(RewardManagerAddress) + RewardManagerPrecompile, err = createRewardManagerPrecompile(precompile.RewardManagerAddress) if err != nil { panic(err) } } -// NewRewardManagerConfig returns a config for a network upgrade at [blockTimestamp] that enables -// RewardManager with the given [admins] and [enableds] as members of the allowlist with [initialConfig] as initial rewards config if specified. -func NewRewardManagerConfig(blockTimestamp *big.Int, admins []common.Address, enableds []common.Address, initialConfig *InitialRewardConfig) *RewardManagerConfig { - return &RewardManagerConfig{ - AllowListConfig: AllowListConfig{ - AllowListAdmins: admins, - EnabledAddresses: enableds, - }, - UpgradeableConfig: UpgradeableConfig{BlockTimestamp: blockTimestamp}, - InitialRewardConfig: initialConfig, - } -} - -// NewDisableRewardManagerConfig returns config for a network upgrade at [blockTimestamp] -// that disables RewardManager. -func NewDisableRewardManagerConfig(blockTimestamp *big.Int) *RewardManagerConfig { - return &RewardManagerConfig{ - UpgradeableConfig: UpgradeableConfig{ - BlockTimestamp: blockTimestamp, - Disable: true, - }, - } -} - -// Equal returns true if [s] is a [*RewardManagerConfig] and it has been configured identical to [c]. -func (c *RewardManagerConfig) Equal(s StatefulPrecompileConfig) bool { - // typecast before comparison - other, ok := (s).(*RewardManagerConfig) - if !ok { - return false - } - // modify this boolean accordingly with your custom RewardManagerConfig, to check if [other] and the current [c] are equal - // if RewardManagerConfig contains only UpgradeableConfig and AllowListConfig you can skip modifying it. - equals := c.UpgradeableConfig.Equal(&other.UpgradeableConfig) && c.AllowListConfig.Equal(&other.AllowListConfig) - if !equals { - return false - } - - if c.InitialRewardConfig == nil { - return other.InitialRewardConfig == nil - } - - return c.InitialRewardConfig.Equal(other.InitialRewardConfig) -} - -// Address returns the address of the RewardManager. Addresses reside under the precompile/params.go -// Select a non-conflicting address and set it in the params.go. -func (c *RewardManagerConfig) Address() common.Address { - return RewardManagerAddress -} - -// Configure configures [state] with the initial configuration. -func (c *RewardManagerConfig) Configure(chainConfig ChainConfig, state StateDB, _ BlockContext) error { - c.AllowListConfig.Configure(state, RewardManagerAddress) - // configure the RewardManager with the given initial configuration - if c.InitialRewardConfig != nil { - return c.InitialRewardConfig.Configure(state) - } else if chainConfig.AllowedFeeRecipients() { - // configure the RewardManager according to chainConfig - EnableAllowFeeRecipients(state) - } else { - // chainConfig does not have any reward address - // if chainConfig does not enable fee recipients - // default to disabling rewards - DisableFeeRewards(state) - } - return nil -} - -// Contract returns the singleton stateful precompiled contract to be used for RewardManager. -func (c *RewardManagerConfig) Contract() StatefulPrecompiledContract { - return RewardManagerPrecompile -} - -func (c *RewardManagerConfig) Verify() error { - if err := c.AllowListConfig.Verify(); err != nil { - return err - } - if c.InitialRewardConfig != nil { - return c.InitialRewardConfig.Verify() - } - return nil -} - -// String returns a string representation of the RewardManagerConfig. -func (c *RewardManagerConfig) String() string { - bytes, _ := json.Marshal(c) - return string(bytes) -} - // GetRewardManagerAllowListStatus returns the role of [address] for the RewardManager list. -func GetRewardManagerAllowListStatus(stateDB StateDB, address common.Address) AllowListRole { - return getAllowListStatus(stateDB, RewardManagerAddress, address) +func GetRewardManagerAllowListStatus(stateDB precompile.StateDB, address common.Address) precompile.AllowListRole { + return precompile.GetAllowListStatus(stateDB, precompile.RewardManagerAddress, address) } // SetRewardManagerAllowListStatus sets the permissions of [address] to [role] for the // RewardManager list. Assumes [role] has already been verified as valid. -func SetRewardManagerAllowListStatus(stateDB StateDB, address common.Address, role AllowListRole) { - setAllowListRole(stateDB, RewardManagerAddress, address, role) +func SetRewardManagerAllowListStatus(stateDB precompile.StateDB, address common.Address, role precompile.AllowListRole) { + precompile.SetAllowListRole(stateDB, precompile.RewardManagerAddress, address, role) } // PackAllowFeeRecipients packs the function selector (first 4 func signature bytes). @@ -219,17 +83,17 @@ func PackAllowFeeRecipients() ([]byte, error) { } // EnableAllowFeeRecipients enables fee recipients. -func EnableAllowFeeRecipients(stateDB StateDB) { - stateDB.SetState(RewardManagerAddress, rewardAddressStorageKey, allowFeeRecipientsAddressValue) +func EnableAllowFeeRecipients(stateDB precompile.StateDB) { + stateDB.SetState(precompile.RewardManagerAddress, rewardAddressStorageKey, allowFeeRecipientsAddressValue) } // DisableRewardAddress disables rewards and burns them by sending to Blackhole Address. -func DisableFeeRewards(stateDB StateDB) { - stateDB.SetState(RewardManagerAddress, rewardAddressStorageKey, constants.BlackholeAddr.Hash()) +func DisableFeeRewards(stateDB precompile.StateDB) { + stateDB.SetState(precompile.RewardManagerAddress, rewardAddressStorageKey, constants.BlackholeAddr.Hash()) } -func allowFeeRecipients(accessibleState PrecompileAccessibleState, caller common.Address, addr common.Address, input []byte, suppliedGas uint64, readOnly bool) (ret []byte, remainingGas uint64, err error) { - if remainingGas, err = deductGas(suppliedGas, AllowFeeRecipientsGasCost); err != nil { +func allowFeeRecipients(accessibleState precompile.PrecompileAccessibleState, caller common.Address, addr common.Address, input []byte, suppliedGas uint64, readOnly bool) (ret []byte, remainingGas uint64, err error) { + if remainingGas, err = precompile.DeductGas(suppliedGas, AllowFeeRecipientsGasCost); err != nil { return nil, 0, err } if readOnly { @@ -242,7 +106,7 @@ func allowFeeRecipients(accessibleState PrecompileAccessibleState, caller common // You can modify/delete this code if you don't want this function to be restricted by the allow list. stateDB := accessibleState.GetStateDB() // Verify that the caller is in the allow list and therefore has the right to modify it - callerStatus := getAllowListStatus(stateDB, RewardManagerAddress, caller) + callerStatus := precompile.GetAllowListStatus(stateDB, precompile.RewardManagerAddress, caller) if !callerStatus.IsEnabled() { return nil, remainingGas, fmt.Errorf("%w: %s", ErrCannotAllowFeeRecipients, caller) } @@ -268,8 +132,8 @@ func PackAreFeeRecipientsAllowedOutput(isAllowed bool) ([]byte, error) { return RewardManagerABI.PackOutput("areFeeRecipientsAllowed", isAllowed) } -func areFeeRecipientsAllowed(accessibleState PrecompileAccessibleState, caller common.Address, addr common.Address, input []byte, suppliedGas uint64, readOnly bool) (ret []byte, remainingGas uint64, err error) { - if remainingGas, err = deductGas(suppliedGas, AreFeeRecipientsAllowedGasCost); err != nil { +func areFeeRecipientsAllowed(accessibleState precompile.PrecompileAccessibleState, caller common.Address, addr common.Address, input []byte, suppliedGas uint64, readOnly bool) (ret []byte, remainingGas uint64, err error) { + if remainingGas, err = precompile.DeductGas(suppliedGas, AreFeeRecipientsAllowedGasCost); err != nil { return nil, 0, err } // no input provided for this function @@ -301,18 +165,18 @@ func PackCurrentRewardAddressOutput(rewardAddress common.Address) ([]byte, error // GetStoredRewardAddress returns the current value of the address stored under rewardAddressStorageKey. // Returns an empty address and true if allow fee recipients is enabled, otherwise returns current reward address and false. -func GetStoredRewardAddress(stateDB StateDB) (common.Address, bool) { - val := stateDB.GetState(RewardManagerAddress, rewardAddressStorageKey) +func GetStoredRewardAddress(stateDB precompile.StateDB) (common.Address, bool) { + val := stateDB.GetState(precompile.RewardManagerAddress, rewardAddressStorageKey) return common.BytesToAddress(val.Bytes()), val == allowFeeRecipientsAddressValue } // StoredRewardAddress stores the given [val] under rewardAddressStorageKey. -func StoreRewardAddress(stateDB StateDB, val common.Address) error { +func StoreRewardAddress(stateDB precompile.StateDB, val common.Address) error { // if input is empty, return an error if val == (common.Address{}) { return ErrEmptyRewardAddress } - stateDB.SetState(RewardManagerAddress, rewardAddressStorageKey, val.Hash()) + stateDB.SetState(precompile.RewardManagerAddress, rewardAddressStorageKey, val.Hash()) return nil } @@ -334,8 +198,8 @@ func UnpackSetRewardAddressInput(input []byte) (common.Address, error) { return unpacked, nil } -func setRewardAddress(accessibleState PrecompileAccessibleState, caller common.Address, addr common.Address, input []byte, suppliedGas uint64, readOnly bool) (ret []byte, remainingGas uint64, err error) { - if remainingGas, err = deductGas(suppliedGas, SetRewardAddressGasCost); err != nil { +func setRewardAddress(accessibleState precompile.PrecompileAccessibleState, caller common.Address, addr common.Address, input []byte, suppliedGas uint64, readOnly bool) (ret []byte, remainingGas uint64, err error) { + if remainingGas, err = precompile.DeductGas(suppliedGas, SetRewardAddressGasCost); err != nil { return nil, 0, err } if readOnly { @@ -354,7 +218,7 @@ func setRewardAddress(accessibleState PrecompileAccessibleState, caller common.A // You can modify/delete this code if you don't want this function to be restricted by the allow list. stateDB := accessibleState.GetStateDB() // Verify that the caller is in the allow list and therefore has the right to modify it - callerStatus := getAllowListStatus(stateDB, RewardManagerAddress, caller) + callerStatus := precompile.GetAllowListStatus(stateDB, precompile.RewardManagerAddress, caller) if !callerStatus.IsEnabled() { return nil, remainingGas, fmt.Errorf("%w: %s", ErrCannotSetRewardAddress, caller) } @@ -370,8 +234,8 @@ func setRewardAddress(accessibleState PrecompileAccessibleState, caller common.A return packedOutput, remainingGas, nil } -func currentRewardAddress(accessibleState PrecompileAccessibleState, caller common.Address, addr common.Address, input []byte, suppliedGas uint64, readOnly bool) (ret []byte, remainingGas uint64, err error) { - if remainingGas, err = deductGas(suppliedGas, CurrentRewardAddressGasCost); err != nil { +func currentRewardAddress(accessibleState precompile.PrecompileAccessibleState, caller common.Address, addr common.Address, input []byte, suppliedGas uint64, readOnly bool) (ret []byte, remainingGas uint64, err error) { + if remainingGas, err = precompile.DeductGas(suppliedGas, CurrentRewardAddressGasCost); err != nil { return nil, 0, err } @@ -393,8 +257,8 @@ func PackDisableRewards() ([]byte, error) { return RewardManagerABI.Pack("disableRewards") } -func disableRewards(accessibleState PrecompileAccessibleState, caller common.Address, addr common.Address, input []byte, suppliedGas uint64, readOnly bool) (ret []byte, remainingGas uint64, err error) { - if remainingGas, err = deductGas(suppliedGas, DisableRewardsGasCost); err != nil { +func disableRewards(accessibleState precompile.PrecompileAccessibleState, caller common.Address, addr common.Address, input []byte, suppliedGas uint64, readOnly bool) (ret []byte, remainingGas uint64, err error) { + if remainingGas, err = precompile.DeductGas(suppliedGas, DisableRewardsGasCost); err != nil { return nil, 0, err } if readOnly { @@ -407,7 +271,7 @@ func disableRewards(accessibleState PrecompileAccessibleState, caller common.Add // You can modify/delete this code if you don't want this function to be restricted by the allow list. stateDB := accessibleState.GetStateDB() // Verify that the caller is in the allow list and therefore has the right to modify it - callerStatus := getAllowListStatus(stateDB, RewardManagerAddress, caller) + callerStatus := precompile.GetAllowListStatus(stateDB, precompile.RewardManagerAddress, caller) if !callerStatus.IsEnabled() { return nil, remainingGas, fmt.Errorf("%w: %s", ErrCannotDisableRewards, caller) } @@ -422,10 +286,10 @@ func disableRewards(accessibleState PrecompileAccessibleState, caller common.Add // createRewardManagerPrecompile returns a StatefulPrecompiledContract with getters and setters for the precompile. // Access to the getters/setters is controlled by an allow list for [precompileAddr]. -func createRewardManagerPrecompile(precompileAddr common.Address) (StatefulPrecompiledContract, error) { - var functions []*statefulPrecompileFunction - functions = append(functions, createAllowListFunctions(precompileAddr)...) - abiFunctionMap := map[string]RunStatefulPrecompileFunc{ +func createRewardManagerPrecompile(precompileAddr common.Address) (precompile.StatefulPrecompiledContract, error) { + var functions []*precompile.StatefulPrecompileFunction + functions = append(functions, precompile.CreateAllowListFunctions(precompileAddr)...) + abiFunctionMap := map[string]precompile.RunStatefulPrecompileFunc{ "allowFeeRecipients": allowFeeRecipients, "areFeeRecipientsAllowed": areFeeRecipientsAllowed, "currentRewardAddress": currentRewardAddress, @@ -438,9 +302,9 @@ func createRewardManagerPrecompile(precompileAddr common.Address) (StatefulPreco if !ok { return nil, fmt.Errorf("given method (%s) does not exist in the ABI", name) } - functions = append(functions, newStatefulPrecompileFunction(method.ID, function)) + functions = append(functions, precompile.NewStatefulPrecompileFunction(method.ID, function)) } // Construct the contract with no fallback function. - return NewStatefulPrecompileContract(nil, functions) + return precompile.NewStatefulPrecompileContract(nil, functions) } diff --git a/precompile/rewardmanager/config_test.go b/precompile/rewardmanager/config_test.go new file mode 100644 index 0000000000..516496876a --- /dev/null +++ b/precompile/rewardmanager/config_test.go @@ -0,0 +1,121 @@ +// (c) 2022 Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package rewardmanager + +import ( + "math/big" + "testing" + + "github.com/ava-labs/subnet-evm/precompile" + "github.com/ethereum/go-ethereum/common" + "github.com/stretchr/testify/require" +) + +func TestVerifyPrecompileUpgrades(t *testing.T) { + admins := []common.Address{{1}} + enableds := []common.Address{{2}} + tests := []struct { + name string + config precompile.StatefulPrecompileConfig + expectedError string + }{ + { + name: "duplicate enableds in config in reward manager allowlist", + config: NewRewardManagerConfig(big.NewInt(3), admins, append(enableds, enableds[0]), nil), + expectedError: "duplicate address", + }, + { + name: "both reward mechanisms should not be activated at the same time in reward manager", + config: NewRewardManagerConfig(big.NewInt(3), admins, enableds, &InitialRewardConfig{ + AllowFeeRecipients: true, + RewardAddress: common.HexToAddress("0x01"), + }), + expectedError: ErrCannotEnableBothRewards.Error(), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + require := require.New(t) + + err := tt.config.Verify() + if tt.expectedError == "" { + require.NoError(err) + } else { + require.ErrorContains(err, tt.expectedError) + } + }) + } +} + +func TestEqualRewardManagerConfig(t *testing.T) { + admins := []common.Address{{1}} + enableds := []common.Address{{2}} + tests := []struct { + name string + config precompile.StatefulPrecompileConfig + other precompile.StatefulPrecompileConfig + expected bool + }{ + { + name: "non-nil config and nil other", + config: NewRewardManagerConfig(big.NewInt(3), admins, enableds, nil), + other: nil, + expected: false, + }, + { + name: "different type", + config: NewRewardManagerConfig(big.NewInt(3), admins, enableds, nil), + other: precompile.NewTxAllowListConfig(big.NewInt(3), []common.Address{{1}}, []common.Address{{2}}), + expected: false, + }, + { + name: "different timestamp", + config: NewRewardManagerConfig(big.NewInt(3), admins, nil, nil), + other: NewRewardManagerConfig(big.NewInt(4), admins, nil, nil), + expected: false, + }, + { + name: "different enabled", + config: NewRewardManagerConfig(big.NewInt(3), admins, nil, nil), + other: NewRewardManagerConfig(big.NewInt(3), admins, enableds, nil), + expected: false, + }, + { + name: "non-nil initial config and nil initial config", + config: NewRewardManagerConfig(big.NewInt(3), admins, nil, &InitialRewardConfig{ + AllowFeeRecipients: true, + }), + other: NewRewardManagerConfig(big.NewInt(3), admins, nil, nil), + expected: false, + }, + { + name: "different initial config", + config: NewRewardManagerConfig(big.NewInt(3), admins, nil, &InitialRewardConfig{ + RewardAddress: common.HexToAddress("0x01"), + }), + other: NewRewardManagerConfig(big.NewInt(3), admins, nil, + &InitialRewardConfig{ + RewardAddress: common.HexToAddress("0x02"), + }), + expected: false, + }, + { + name: "same config", + config: NewRewardManagerConfig(big.NewInt(3), admins, nil, &InitialRewardConfig{ + RewardAddress: common.HexToAddress("0x01"), + }), + other: NewRewardManagerConfig(big.NewInt(3), admins, nil, &InitialRewardConfig{ + RewardAddress: common.HexToAddress("0x01"), + }), + expected: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + require := require.New(t) + + require.Equal(tt.expected, tt.config.Equal(tt.other)) + }) + } +} diff --git a/precompile/reward_manager.abi b/precompile/rewardmanager/contract.abi similarity index 100% rename from precompile/reward_manager.abi rename to precompile/rewardmanager/contract.abi diff --git a/precompile/rewardmanager/contract.go b/precompile/rewardmanager/contract.go new file mode 100644 index 0000000000..c5889d0e83 --- /dev/null +++ b/precompile/rewardmanager/contract.go @@ -0,0 +1,150 @@ +// (c) 2019-2020, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +// Code generated +// This file is a generated precompile contract with stubbed abstract functions. + +package rewardmanager + +import ( + "encoding/json" + "math/big" + + "github.com/ava-labs/subnet-evm/precompile" + "github.com/ethereum/go-ethereum/common" +) + +type InitialRewardConfig struct { + AllowFeeRecipients bool `json:"allowFeeRecipients"` + RewardAddress common.Address `json:"rewardAddress,omitempty"` +} + +func (i *InitialRewardConfig) Verify() error { + switch { + case i.AllowFeeRecipients && i.RewardAddress != (common.Address{}): + return ErrCannotEnableBothRewards + default: + return nil + } +} + +func (c *InitialRewardConfig) Equal(other *InitialRewardConfig) bool { + if other == nil { + return false + } + + return c.AllowFeeRecipients == other.AllowFeeRecipients && c.RewardAddress == other.RewardAddress +} + +func (i *InitialRewardConfig) Configure(state precompile.StateDB) error { + // enable allow fee recipients + if i.AllowFeeRecipients { + EnableAllowFeeRecipients(state) + } else if i.RewardAddress == (common.Address{}) { + // if reward address is empty and allow fee recipients is false + // then disable rewards + DisableFeeRewards(state) + } else { + // set reward address + return StoreRewardAddress(state, i.RewardAddress) + } + return nil +} + +// RewardManagerConfig implements the StatefulPrecompileConfig +// interface while adding in the RewardManager specific precompile config. +type RewardManagerConfig struct { + precompile.AllowListConfig + precompile.UpgradeableConfig + InitialRewardConfig *InitialRewardConfig `json:"initialRewardConfig,omitempty"` +} + +// NewRewardManagerConfig returns a config for a network upgrade at [blockTimestamp] that enables +// RewardManager with the given [admins] and [enableds] as members of the allowlist with [initialConfig] as initial rewards config if specified. +func NewRewardManagerConfig(blockTimestamp *big.Int, admins []common.Address, enableds []common.Address, initialConfig *InitialRewardConfig) *RewardManagerConfig { + return &RewardManagerConfig{ + AllowListConfig: precompile.AllowListConfig{ + AllowListAdmins: admins, + EnabledAddresses: enableds, + }, + UpgradeableConfig: precompile.UpgradeableConfig{BlockTimestamp: blockTimestamp}, + InitialRewardConfig: initialConfig, + } +} + +// NewDisableRewardManagerConfig returns config for a network upgrade at [blockTimestamp] +// that disables RewardManager. +func NewDisableRewardManagerConfig(blockTimestamp *big.Int) *RewardManagerConfig { + return &RewardManagerConfig{ + UpgradeableConfig: precompile.UpgradeableConfig{ + BlockTimestamp: blockTimestamp, + Disable: true, + }, + } +} + +// Equal returns true if [s] is a [*RewardManagerConfig] and it has been configured identical to [c]. +func (c *RewardManagerConfig) Equal(s precompile.StatefulPrecompileConfig) bool { + // typecast before comparison + other, ok := (s).(*RewardManagerConfig) + if !ok { + return false + } + // modify this boolean accordingly with your custom RewardManagerConfig, to check if [other] and the current [c] are equal + // if RewardManagerConfig contains only UpgradeableConfig and precompile.AllowListConfig you can skip modifying it. + equals := c.UpgradeableConfig.Equal(&other.UpgradeableConfig) && c.AllowListConfig.Equal(&other.AllowListConfig) + if !equals { + return false + } + + if c.InitialRewardConfig == nil { + return other.InitialRewardConfig == nil + } + + return c.InitialRewardConfig.Equal(other.InitialRewardConfig) +} + +// Address returns the address of the RewardManager. Addresses reside under the precompile/params.go +// Select a non-conflicting address and set it in the params.go. +func (c *RewardManagerConfig) Address() common.Address { + return precompile.RewardManagerAddress +} + +// Configure configures [state] with the initial configuration. +func (c *RewardManagerConfig) Configure(chainConfig precompile.ChainConfig, state precompile.StateDB, _ precompile.BlockContext) error { + c.AllowListConfig.Configure(state, precompile.RewardManagerAddress) + // configure the RewardManager with the given initial configuration + if c.InitialRewardConfig != nil { + return c.InitialRewardConfig.Configure(state) + } else if chainConfig.AllowedFeeRecipients() { + // configure the RewardManager according to chainConfig + EnableAllowFeeRecipients(state) + } else { + // chainConfig does not have any reward address + // if chainConfig does not enable fee recipients + // default to disabling rewards + DisableFeeRewards(state) + } + return nil +} + +// Contract returns the singleton stateful precompiled contract to be used for RewardManager. +func (c *RewardManagerConfig) Contract() precompile.StatefulPrecompiledContract { + return RewardManagerPrecompile +} + +func (c *RewardManagerConfig) Verify() error { + if err := c.AllowListConfig.Verify(); err != nil { + return err + } + if c.InitialRewardConfig != nil { + return c.InitialRewardConfig.Verify() + } + return nil +} + +// String returns a string representation of the RewardManagerConfig. +func (c *RewardManagerConfig) String() string { + bytes, _ := json.Marshal(c) + return string(bytes) +} diff --git a/precompile/tx_allow_list.go b/precompile/tx_allow_list.go index 4ab39a8f04..d5a41ccdc2 100644 --- a/precompile/tx_allow_list.go +++ b/precompile/tx_allow_list.go @@ -83,12 +83,12 @@ func (c *TxAllowListConfig) String() string { // GetTxAllowListStatus returns the role of [address] for the contract deployer // allow list. func GetTxAllowListStatus(stateDB StateDB, address common.Address) AllowListRole { - return getAllowListStatus(stateDB, TxAllowListAddress, address) + return GetAllowListStatus(stateDB, TxAllowListAddress, address) } // SetTxAllowListStatus sets the permissions of [address] to [role] for the // tx allow list. // assumes [role] has already been verified as valid. func SetTxAllowListStatus(stateDB StateDB, address common.Address, role AllowListRole) { - setAllowListRole(stateDB, TxAllowListAddress, address, role) + SetAllowListRole(stateDB, TxAllowListAddress, address, role) } diff --git a/precompile/utils.go b/precompile/utils.go index 6d779c251e..ee3f7accf4 100644 --- a/precompile/utils.go +++ b/precompile/utils.go @@ -26,8 +26,8 @@ func CalculateFunctionSelector(functionSignature string) []byte { return hash[:4] } -// deductGas checks if [suppliedGas] is sufficient against [requiredGas] and deducts [requiredGas] from [suppliedGas]. -func deductGas(suppliedGas uint64, requiredGas uint64) (uint64, error) { +// DeductGas checks if [suppliedGas] is sufficient against [requiredGas] and deducts [requiredGas] from [suppliedGas]. +func DeductGas(suppliedGas uint64, requiredGas uint64) (uint64, error) { if suppliedGas < requiredGas { return 0, vmerrs.ErrOutOfGas } From 859b2b500807e58245219c21277b63ea4a7070a7 Mon Sep 17 00:00:00 2001 From: Ceyhun Onur Date: Fri, 23 Dec 2022 17:18:42 +0300 Subject: [PATCH 09/23] rename files --- precompile/rewardmanager/config.go | 358 ++++++++------------------- precompile/rewardmanager/contract.go | 358 +++++++++++++++++++-------- 2 files changed, 358 insertions(+), 358 deletions(-) diff --git a/precompile/rewardmanager/config.go b/precompile/rewardmanager/config.go index 5287b16b2b..c5889d0e83 100644 --- a/precompile/rewardmanager/config.go +++ b/precompile/rewardmanager/config.go @@ -7,304 +7,144 @@ package rewardmanager import ( - "errors" - "fmt" - "strings" + "encoding/json" + "math/big" - "github.com/ava-labs/subnet-evm/accounts/abi" - "github.com/ava-labs/subnet-evm/constants" "github.com/ava-labs/subnet-evm/precompile" - "github.com/ava-labs/subnet-evm/vmerrs" - - _ "embed" - "github.com/ethereum/go-ethereum/common" ) -const ( - AllowFeeRecipientsGasCost uint64 = (precompile.WriteGasCostPerSlot) + precompile.ReadAllowListGasCost // write 1 slot + read allow list - AreFeeRecipientsAllowedGasCost uint64 = precompile.ReadAllowListGasCost - CurrentRewardAddressGasCost uint64 = precompile.ReadAllowListGasCost - DisableRewardsGasCost uint64 = (precompile.WriteGasCostPerSlot) + precompile.ReadAllowListGasCost // write 1 slot + read allow list - SetRewardAddressGasCost uint64 = (precompile.WriteGasCostPerSlot) + precompile.ReadAllowListGasCost // write 1 slot + read allow list -) - -// Singleton StatefulPrecompiledContract and signatures. -var ( - _ precompile.StatefulPrecompileConfig = &RewardManagerConfig{} - - ErrCannotAllowFeeRecipients = errors.New("non-enabled cannot call allowFeeRecipients") - ErrCannotAreFeeRecipientsAllowed = errors.New("non-enabled cannot call areFeeRecipientsAllowed") - ErrCannotCurrentRewardAddress = errors.New("non-enabled cannot call currentRewardAddress") - ErrCannotDisableRewards = errors.New("non-enabled cannot call disableRewards") - ErrCannotSetRewardAddress = errors.New("non-enabled cannot call setRewardAddress") - - ErrCannotEnableBothRewards = errors.New("cannot enable both fee recipients and reward address at the same time") - ErrEmptyRewardAddress = errors.New("reward address cannot be empty") - - // RewardManagerRawABI contains the raw ABI of RewardManager contract. - //go:embed reward_manager.abi - RewardManagerRawABI string - - RewardManagerABI abi.ABI // will be initialized by init function - RewardManagerPrecompile precompile.StatefulPrecompiledContract // will be initialized by init function - - rewardAddressStorageKey = common.Hash{'r', 'a', 's', 'k'} - allowFeeRecipientsAddressValue = common.Hash{'a', 'f', 'r', 'a', 'v'} -) - -func init() { - parsed, err := abi.JSON(strings.NewReader(RewardManagerRawABI)) - if err != nil { - panic(err) - } - RewardManagerABI = parsed - RewardManagerPrecompile, err = createRewardManagerPrecompile(precompile.RewardManagerAddress) - if err != nil { - panic(err) - } -} - -// GetRewardManagerAllowListStatus returns the role of [address] for the RewardManager list. -func GetRewardManagerAllowListStatus(stateDB precompile.StateDB, address common.Address) precompile.AllowListRole { - return precompile.GetAllowListStatus(stateDB, precompile.RewardManagerAddress, address) +type InitialRewardConfig struct { + AllowFeeRecipients bool `json:"allowFeeRecipients"` + RewardAddress common.Address `json:"rewardAddress,omitempty"` } -// SetRewardManagerAllowListStatus sets the permissions of [address] to [role] for the -// RewardManager list. Assumes [role] has already been verified as valid. -func SetRewardManagerAllowListStatus(stateDB precompile.StateDB, address common.Address, role precompile.AllowListRole) { - precompile.SetAllowListRole(stateDB, precompile.RewardManagerAddress, address, role) -} - -// PackAllowFeeRecipients packs the function selector (first 4 func signature bytes). -// This function is mostly used for tests. -func PackAllowFeeRecipients() ([]byte, error) { - return RewardManagerABI.Pack("allowFeeRecipients") -} - -// EnableAllowFeeRecipients enables fee recipients. -func EnableAllowFeeRecipients(stateDB precompile.StateDB) { - stateDB.SetState(precompile.RewardManagerAddress, rewardAddressStorageKey, allowFeeRecipientsAddressValue) -} - -// DisableRewardAddress disables rewards and burns them by sending to Blackhole Address. -func DisableFeeRewards(stateDB precompile.StateDB) { - stateDB.SetState(precompile.RewardManagerAddress, rewardAddressStorageKey, constants.BlackholeAddr.Hash()) -} - -func allowFeeRecipients(accessibleState precompile.PrecompileAccessibleState, caller common.Address, addr common.Address, input []byte, suppliedGas uint64, readOnly bool) (ret []byte, remainingGas uint64, err error) { - if remainingGas, err = precompile.DeductGas(suppliedGas, AllowFeeRecipientsGasCost); err != nil { - return nil, 0, err - } - if readOnly { - return nil, remainingGas, vmerrs.ErrWriteProtection - } - // no input provided for this function - - // Allow list is enabled and AllowFeeRecipients is a state-changer function. - // This part of the code restricts the function to be called only by enabled/admin addresses in the allow list. - // You can modify/delete this code if you don't want this function to be restricted by the allow list. - stateDB := accessibleState.GetStateDB() - // Verify that the caller is in the allow list and therefore has the right to modify it - callerStatus := precompile.GetAllowListStatus(stateDB, precompile.RewardManagerAddress, caller) - if !callerStatus.IsEnabled() { - return nil, remainingGas, fmt.Errorf("%w: %s", ErrCannotAllowFeeRecipients, caller) +func (i *InitialRewardConfig) Verify() error { + switch { + case i.AllowFeeRecipients && i.RewardAddress != (common.Address{}): + return ErrCannotEnableBothRewards + default: + return nil } - // allow list code ends here. - - // this function does not return an output, leave this one as is - EnableAllowFeeRecipients(stateDB) - packedOutput := []byte{} - - // Return the packed output and the remaining gas - return packedOutput, remainingGas, nil } -// PackAreFeeRecipientsAllowed packs the include selector (first 4 func signature bytes). -// This function is mostly used for tests. -func PackAreFeeRecipientsAllowed() ([]byte, error) { - return RewardManagerABI.Pack("areFeeRecipientsAllowed") -} - -// PackAreFeeRecipientsAllowedOutput attempts to pack given isAllowed of type bool -// to conform the ABI outputs. -func PackAreFeeRecipientsAllowedOutput(isAllowed bool) ([]byte, error) { - return RewardManagerABI.PackOutput("areFeeRecipientsAllowed", isAllowed) -} - -func areFeeRecipientsAllowed(accessibleState precompile.PrecompileAccessibleState, caller common.Address, addr common.Address, input []byte, suppliedGas uint64, readOnly bool) (ret []byte, remainingGas uint64, err error) { - if remainingGas, err = precompile.DeductGas(suppliedGas, AreFeeRecipientsAllowedGasCost); err != nil { - return nil, 0, err +func (c *InitialRewardConfig) Equal(other *InitialRewardConfig) bool { + if other == nil { + return false } - // no input provided for this function - - stateDB := accessibleState.GetStateDB() - var output bool - _, output = GetStoredRewardAddress(stateDB) - - packedOutput, err := PackAreFeeRecipientsAllowedOutput(output) - if err != nil { - return nil, remainingGas, err - } - - // Return the packed output and the remaining gas - return packedOutput, remainingGas, nil -} - -// PackCurrentRewardAddress packs the include selector (first 4 func signature bytes). -// This function is mostly used for tests. -func PackCurrentRewardAddress() ([]byte, error) { - return RewardManagerABI.Pack("currentRewardAddress") -} -// PackCurrentRewardAddressOutput attempts to pack given rewardAddress of type common.Address -// to conform the ABI outputs. -func PackCurrentRewardAddressOutput(rewardAddress common.Address) ([]byte, error) { - return RewardManagerABI.PackOutput("currentRewardAddress", rewardAddress) + return c.AllowFeeRecipients == other.AllowFeeRecipients && c.RewardAddress == other.RewardAddress } -// GetStoredRewardAddress returns the current value of the address stored under rewardAddressStorageKey. -// Returns an empty address and true if allow fee recipients is enabled, otherwise returns current reward address and false. -func GetStoredRewardAddress(stateDB precompile.StateDB) (common.Address, bool) { - val := stateDB.GetState(precompile.RewardManagerAddress, rewardAddressStorageKey) - return common.BytesToAddress(val.Bytes()), val == allowFeeRecipientsAddressValue -} - -// StoredRewardAddress stores the given [val] under rewardAddressStorageKey. -func StoreRewardAddress(stateDB precompile.StateDB, val common.Address) error { - // if input is empty, return an error - if val == (common.Address{}) { - return ErrEmptyRewardAddress +func (i *InitialRewardConfig) Configure(state precompile.StateDB) error { + // enable allow fee recipients + if i.AllowFeeRecipients { + EnableAllowFeeRecipients(state) + } else if i.RewardAddress == (common.Address{}) { + // if reward address is empty and allow fee recipients is false + // then disable rewards + DisableFeeRewards(state) + } else { + // set reward address + return StoreRewardAddress(state, i.RewardAddress) } - stateDB.SetState(precompile.RewardManagerAddress, rewardAddressStorageKey, val.Hash()) return nil } -// PackSetRewardAddress packs [addr] of type common.Address into the appropriate arguments for setRewardAddress. -// the packed bytes include selector (first 4 func signature bytes). -// This function is mostly used for tests. -func PackSetRewardAddress(addr common.Address) ([]byte, error) { - return RewardManagerABI.Pack("setRewardAddress", addr) +// RewardManagerConfig implements the StatefulPrecompileConfig +// interface while adding in the RewardManager specific precompile config. +type RewardManagerConfig struct { + precompile.AllowListConfig + precompile.UpgradeableConfig + InitialRewardConfig *InitialRewardConfig `json:"initialRewardConfig,omitempty"` } -// UnpackSetRewardAddressInput attempts to unpack [input] into the common.Address type argument -// assumes that [input] does not include selector (omits first 4 func signature bytes) -func UnpackSetRewardAddressInput(input []byte) (common.Address, error) { - res, err := RewardManagerABI.UnpackInput("setRewardAddress", input) - if err != nil { - return common.Address{}, err +// NewRewardManagerConfig returns a config for a network upgrade at [blockTimestamp] that enables +// RewardManager with the given [admins] and [enableds] as members of the allowlist with [initialConfig] as initial rewards config if specified. +func NewRewardManagerConfig(blockTimestamp *big.Int, admins []common.Address, enableds []common.Address, initialConfig *InitialRewardConfig) *RewardManagerConfig { + return &RewardManagerConfig{ + AllowListConfig: precompile.AllowListConfig{ + AllowListAdmins: admins, + EnabledAddresses: enableds, + }, + UpgradeableConfig: precompile.UpgradeableConfig{BlockTimestamp: blockTimestamp}, + InitialRewardConfig: initialConfig, } - unpacked := *abi.ConvertType(res[0], new(common.Address)).(*common.Address) - return unpacked, nil } -func setRewardAddress(accessibleState precompile.PrecompileAccessibleState, caller common.Address, addr common.Address, input []byte, suppliedGas uint64, readOnly bool) (ret []byte, remainingGas uint64, err error) { - if remainingGas, err = precompile.DeductGas(suppliedGas, SetRewardAddressGasCost); err != nil { - return nil, 0, err - } - if readOnly { - return nil, remainingGas, vmerrs.ErrWriteProtection - } - // attempts to unpack [input] into the arguments to the SetRewardAddressInput. - // Assumes that [input] does not include selector - // You can use unpacked [inputStruct] variable in your code - inputStruct, err := UnpackSetRewardAddressInput(input) - if err != nil { - return nil, remainingGas, err - } - - // Allow list is enabled and SetRewardAddress is a state-changer function. - // This part of the code restricts the function to be called only by enabled/admin addresses in the allow list. - // You can modify/delete this code if you don't want this function to be restricted by the allow list. - stateDB := accessibleState.GetStateDB() - // Verify that the caller is in the allow list and therefore has the right to modify it - callerStatus := precompile.GetAllowListStatus(stateDB, precompile.RewardManagerAddress, caller) - if !callerStatus.IsEnabled() { - return nil, remainingGas, fmt.Errorf("%w: %s", ErrCannotSetRewardAddress, caller) - } - // allow list code ends here. - - if err := StoreRewardAddress(stateDB, inputStruct); err != nil { - return nil, remainingGas, err +// NewDisableRewardManagerConfig returns config for a network upgrade at [blockTimestamp] +// that disables RewardManager. +func NewDisableRewardManagerConfig(blockTimestamp *big.Int) *RewardManagerConfig { + return &RewardManagerConfig{ + UpgradeableConfig: precompile.UpgradeableConfig{ + BlockTimestamp: blockTimestamp, + Disable: true, + }, } - // this function does not return an output, leave this one as is - packedOutput := []byte{} - - // Return the packed output and the remaining gas - return packedOutput, remainingGas, nil } -func currentRewardAddress(accessibleState precompile.PrecompileAccessibleState, caller common.Address, addr common.Address, input []byte, suppliedGas uint64, readOnly bool) (ret []byte, remainingGas uint64, err error) { - if remainingGas, err = precompile.DeductGas(suppliedGas, CurrentRewardAddressGasCost); err != nil { - return nil, 0, err +// Equal returns true if [s] is a [*RewardManagerConfig] and it has been configured identical to [c]. +func (c *RewardManagerConfig) Equal(s precompile.StatefulPrecompileConfig) bool { + // typecast before comparison + other, ok := (s).(*RewardManagerConfig) + if !ok { + return false + } + // modify this boolean accordingly with your custom RewardManagerConfig, to check if [other] and the current [c] are equal + // if RewardManagerConfig contains only UpgradeableConfig and precompile.AllowListConfig you can skip modifying it. + equals := c.UpgradeableConfig.Equal(&other.UpgradeableConfig) && c.AllowListConfig.Equal(&other.AllowListConfig) + if !equals { + return false } - // no input provided for this function - stateDB := accessibleState.GetStateDB() - output, _ := GetStoredRewardAddress(stateDB) - packedOutput, err := PackCurrentRewardAddressOutput(output) - if err != nil { - return nil, remainingGas, err + if c.InitialRewardConfig == nil { + return other.InitialRewardConfig == nil } - // Return the packed output and the remaining gas - return packedOutput, remainingGas, nil + return c.InitialRewardConfig.Equal(other.InitialRewardConfig) } -// PackDisableRewards packs the include selector (first 4 func signature bytes). -// This function is mostly used for tests. -func PackDisableRewards() ([]byte, error) { - return RewardManagerABI.Pack("disableRewards") +// Address returns the address of the RewardManager. Addresses reside under the precompile/params.go +// Select a non-conflicting address and set it in the params.go. +func (c *RewardManagerConfig) Address() common.Address { + return precompile.RewardManagerAddress } -func disableRewards(accessibleState precompile.PrecompileAccessibleState, caller common.Address, addr common.Address, input []byte, suppliedGas uint64, readOnly bool) (ret []byte, remainingGas uint64, err error) { - if remainingGas, err = precompile.DeductGas(suppliedGas, DisableRewardsGasCost); err != nil { - return nil, 0, err - } - if readOnly { - return nil, remainingGas, vmerrs.ErrWriteProtection - } - // no input provided for this function - - // Allow list is enabled and DisableRewards is a state-changer function. - // This part of the code restricts the function to be called only by enabled/admin addresses in the allow list. - // You can modify/delete this code if you don't want this function to be restricted by the allow list. - stateDB := accessibleState.GetStateDB() - // Verify that the caller is in the allow list and therefore has the right to modify it - callerStatus := precompile.GetAllowListStatus(stateDB, precompile.RewardManagerAddress, caller) - if !callerStatus.IsEnabled() { - return nil, remainingGas, fmt.Errorf("%w: %s", ErrCannotDisableRewards, caller) +// Configure configures [state] with the initial configuration. +func (c *RewardManagerConfig) Configure(chainConfig precompile.ChainConfig, state precompile.StateDB, _ precompile.BlockContext) error { + c.AllowListConfig.Configure(state, precompile.RewardManagerAddress) + // configure the RewardManager with the given initial configuration + if c.InitialRewardConfig != nil { + return c.InitialRewardConfig.Configure(state) + } else if chainConfig.AllowedFeeRecipients() { + // configure the RewardManager according to chainConfig + EnableAllowFeeRecipients(state) + } else { + // chainConfig does not have any reward address + // if chainConfig does not enable fee recipients + // default to disabling rewards + DisableFeeRewards(state) } - // allow list code ends here. - DisableFeeRewards(stateDB) - // this function does not return an output, leave this one as is - packedOutput := []byte{} + return nil +} - // Return the packed output and the remaining gas - return packedOutput, remainingGas, nil +// Contract returns the singleton stateful precompiled contract to be used for RewardManager. +func (c *RewardManagerConfig) Contract() precompile.StatefulPrecompiledContract { + return RewardManagerPrecompile } -// createRewardManagerPrecompile returns a StatefulPrecompiledContract with getters and setters for the precompile. -// Access to the getters/setters is controlled by an allow list for [precompileAddr]. -func createRewardManagerPrecompile(precompileAddr common.Address) (precompile.StatefulPrecompiledContract, error) { - var functions []*precompile.StatefulPrecompileFunction - functions = append(functions, precompile.CreateAllowListFunctions(precompileAddr)...) - abiFunctionMap := map[string]precompile.RunStatefulPrecompileFunc{ - "allowFeeRecipients": allowFeeRecipients, - "areFeeRecipientsAllowed": areFeeRecipientsAllowed, - "currentRewardAddress": currentRewardAddress, - "disableRewards": disableRewards, - "setRewardAddress": setRewardAddress, +func (c *RewardManagerConfig) Verify() error { + if err := c.AllowListConfig.Verify(); err != nil { + return err } - - for name, function := range abiFunctionMap { - method, ok := RewardManagerABI.Methods[name] - if !ok { - return nil, fmt.Errorf("given method (%s) does not exist in the ABI", name) - } - functions = append(functions, precompile.NewStatefulPrecompileFunction(method.ID, function)) + if c.InitialRewardConfig != nil { + return c.InitialRewardConfig.Verify() } + return nil +} - // Construct the contract with no fallback function. - return precompile.NewStatefulPrecompileContract(nil, functions) +// String returns a string representation of the RewardManagerConfig. +func (c *RewardManagerConfig) String() string { + bytes, _ := json.Marshal(c) + return string(bytes) } diff --git a/precompile/rewardmanager/contract.go b/precompile/rewardmanager/contract.go index c5889d0e83..5287b16b2b 100644 --- a/precompile/rewardmanager/contract.go +++ b/precompile/rewardmanager/contract.go @@ -7,144 +7,304 @@ package rewardmanager import ( - "encoding/json" - "math/big" + "errors" + "fmt" + "strings" + "github.com/ava-labs/subnet-evm/accounts/abi" + "github.com/ava-labs/subnet-evm/constants" "github.com/ava-labs/subnet-evm/precompile" + "github.com/ava-labs/subnet-evm/vmerrs" + + _ "embed" + "github.com/ethereum/go-ethereum/common" ) -type InitialRewardConfig struct { - AllowFeeRecipients bool `json:"allowFeeRecipients"` - RewardAddress common.Address `json:"rewardAddress,omitempty"` -} +const ( + AllowFeeRecipientsGasCost uint64 = (precompile.WriteGasCostPerSlot) + precompile.ReadAllowListGasCost // write 1 slot + read allow list + AreFeeRecipientsAllowedGasCost uint64 = precompile.ReadAllowListGasCost + CurrentRewardAddressGasCost uint64 = precompile.ReadAllowListGasCost + DisableRewardsGasCost uint64 = (precompile.WriteGasCostPerSlot) + precompile.ReadAllowListGasCost // write 1 slot + read allow list + SetRewardAddressGasCost uint64 = (precompile.WriteGasCostPerSlot) + precompile.ReadAllowListGasCost // write 1 slot + read allow list +) + +// Singleton StatefulPrecompiledContract and signatures. +var ( + _ precompile.StatefulPrecompileConfig = &RewardManagerConfig{} + + ErrCannotAllowFeeRecipients = errors.New("non-enabled cannot call allowFeeRecipients") + ErrCannotAreFeeRecipientsAllowed = errors.New("non-enabled cannot call areFeeRecipientsAllowed") + ErrCannotCurrentRewardAddress = errors.New("non-enabled cannot call currentRewardAddress") + ErrCannotDisableRewards = errors.New("non-enabled cannot call disableRewards") + ErrCannotSetRewardAddress = errors.New("non-enabled cannot call setRewardAddress") + + ErrCannotEnableBothRewards = errors.New("cannot enable both fee recipients and reward address at the same time") + ErrEmptyRewardAddress = errors.New("reward address cannot be empty") + + // RewardManagerRawABI contains the raw ABI of RewardManager contract. + //go:embed reward_manager.abi + RewardManagerRawABI string -func (i *InitialRewardConfig) Verify() error { - switch { - case i.AllowFeeRecipients && i.RewardAddress != (common.Address{}): - return ErrCannotEnableBothRewards - default: - return nil + RewardManagerABI abi.ABI // will be initialized by init function + RewardManagerPrecompile precompile.StatefulPrecompiledContract // will be initialized by init function + + rewardAddressStorageKey = common.Hash{'r', 'a', 's', 'k'} + allowFeeRecipientsAddressValue = common.Hash{'a', 'f', 'r', 'a', 'v'} +) + +func init() { + parsed, err := abi.JSON(strings.NewReader(RewardManagerRawABI)) + if err != nil { + panic(err) + } + RewardManagerABI = parsed + RewardManagerPrecompile, err = createRewardManagerPrecompile(precompile.RewardManagerAddress) + if err != nil { + panic(err) } } -func (c *InitialRewardConfig) Equal(other *InitialRewardConfig) bool { - if other == nil { - return false +// GetRewardManagerAllowListStatus returns the role of [address] for the RewardManager list. +func GetRewardManagerAllowListStatus(stateDB precompile.StateDB, address common.Address) precompile.AllowListRole { + return precompile.GetAllowListStatus(stateDB, precompile.RewardManagerAddress, address) +} + +// SetRewardManagerAllowListStatus sets the permissions of [address] to [role] for the +// RewardManager list. Assumes [role] has already been verified as valid. +func SetRewardManagerAllowListStatus(stateDB precompile.StateDB, address common.Address, role precompile.AllowListRole) { + precompile.SetAllowListRole(stateDB, precompile.RewardManagerAddress, address, role) +} + +// PackAllowFeeRecipients packs the function selector (first 4 func signature bytes). +// This function is mostly used for tests. +func PackAllowFeeRecipients() ([]byte, error) { + return RewardManagerABI.Pack("allowFeeRecipients") +} + +// EnableAllowFeeRecipients enables fee recipients. +func EnableAllowFeeRecipients(stateDB precompile.StateDB) { + stateDB.SetState(precompile.RewardManagerAddress, rewardAddressStorageKey, allowFeeRecipientsAddressValue) +} + +// DisableRewardAddress disables rewards and burns them by sending to Blackhole Address. +func DisableFeeRewards(stateDB precompile.StateDB) { + stateDB.SetState(precompile.RewardManagerAddress, rewardAddressStorageKey, constants.BlackholeAddr.Hash()) +} + +func allowFeeRecipients(accessibleState precompile.PrecompileAccessibleState, caller common.Address, addr common.Address, input []byte, suppliedGas uint64, readOnly bool) (ret []byte, remainingGas uint64, err error) { + if remainingGas, err = precompile.DeductGas(suppliedGas, AllowFeeRecipientsGasCost); err != nil { + return nil, 0, err } + if readOnly { + return nil, remainingGas, vmerrs.ErrWriteProtection + } + // no input provided for this function + + // Allow list is enabled and AllowFeeRecipients is a state-changer function. + // This part of the code restricts the function to be called only by enabled/admin addresses in the allow list. + // You can modify/delete this code if you don't want this function to be restricted by the allow list. + stateDB := accessibleState.GetStateDB() + // Verify that the caller is in the allow list and therefore has the right to modify it + callerStatus := precompile.GetAllowListStatus(stateDB, precompile.RewardManagerAddress, caller) + if !callerStatus.IsEnabled() { + return nil, remainingGas, fmt.Errorf("%w: %s", ErrCannotAllowFeeRecipients, caller) + } + // allow list code ends here. + + // this function does not return an output, leave this one as is + EnableAllowFeeRecipients(stateDB) + packedOutput := []byte{} - return c.AllowFeeRecipients == other.AllowFeeRecipients && c.RewardAddress == other.RewardAddress + // Return the packed output and the remaining gas + return packedOutput, remainingGas, nil } -func (i *InitialRewardConfig) Configure(state precompile.StateDB) error { - // enable allow fee recipients - if i.AllowFeeRecipients { - EnableAllowFeeRecipients(state) - } else if i.RewardAddress == (common.Address{}) { - // if reward address is empty and allow fee recipients is false - // then disable rewards - DisableFeeRewards(state) - } else { - // set reward address - return StoreRewardAddress(state, i.RewardAddress) +// PackAreFeeRecipientsAllowed packs the include selector (first 4 func signature bytes). +// This function is mostly used for tests. +func PackAreFeeRecipientsAllowed() ([]byte, error) { + return RewardManagerABI.Pack("areFeeRecipientsAllowed") +} + +// PackAreFeeRecipientsAllowedOutput attempts to pack given isAllowed of type bool +// to conform the ABI outputs. +func PackAreFeeRecipientsAllowedOutput(isAllowed bool) ([]byte, error) { + return RewardManagerABI.PackOutput("areFeeRecipientsAllowed", isAllowed) +} + +func areFeeRecipientsAllowed(accessibleState precompile.PrecompileAccessibleState, caller common.Address, addr common.Address, input []byte, suppliedGas uint64, readOnly bool) (ret []byte, remainingGas uint64, err error) { + if remainingGas, err = precompile.DeductGas(suppliedGas, AreFeeRecipientsAllowedGasCost); err != nil { + return nil, 0, err } - return nil + // no input provided for this function + + stateDB := accessibleState.GetStateDB() + var output bool + _, output = GetStoredRewardAddress(stateDB) + + packedOutput, err := PackAreFeeRecipientsAllowedOutput(output) + if err != nil { + return nil, remainingGas, err + } + + // Return the packed output and the remaining gas + return packedOutput, remainingGas, nil +} + +// PackCurrentRewardAddress packs the include selector (first 4 func signature bytes). +// This function is mostly used for tests. +func PackCurrentRewardAddress() ([]byte, error) { + return RewardManagerABI.Pack("currentRewardAddress") +} + +// PackCurrentRewardAddressOutput attempts to pack given rewardAddress of type common.Address +// to conform the ABI outputs. +func PackCurrentRewardAddressOutput(rewardAddress common.Address) ([]byte, error) { + return RewardManagerABI.PackOutput("currentRewardAddress", rewardAddress) } -// RewardManagerConfig implements the StatefulPrecompileConfig -// interface while adding in the RewardManager specific precompile config. -type RewardManagerConfig struct { - precompile.AllowListConfig - precompile.UpgradeableConfig - InitialRewardConfig *InitialRewardConfig `json:"initialRewardConfig,omitempty"` +// GetStoredRewardAddress returns the current value of the address stored under rewardAddressStorageKey. +// Returns an empty address and true if allow fee recipients is enabled, otherwise returns current reward address and false. +func GetStoredRewardAddress(stateDB precompile.StateDB) (common.Address, bool) { + val := stateDB.GetState(precompile.RewardManagerAddress, rewardAddressStorageKey) + return common.BytesToAddress(val.Bytes()), val == allowFeeRecipientsAddressValue } -// NewRewardManagerConfig returns a config for a network upgrade at [blockTimestamp] that enables -// RewardManager with the given [admins] and [enableds] as members of the allowlist with [initialConfig] as initial rewards config if specified. -func NewRewardManagerConfig(blockTimestamp *big.Int, admins []common.Address, enableds []common.Address, initialConfig *InitialRewardConfig) *RewardManagerConfig { - return &RewardManagerConfig{ - AllowListConfig: precompile.AllowListConfig{ - AllowListAdmins: admins, - EnabledAddresses: enableds, - }, - UpgradeableConfig: precompile.UpgradeableConfig{BlockTimestamp: blockTimestamp}, - InitialRewardConfig: initialConfig, +// StoredRewardAddress stores the given [val] under rewardAddressStorageKey. +func StoreRewardAddress(stateDB precompile.StateDB, val common.Address) error { + // if input is empty, return an error + if val == (common.Address{}) { + return ErrEmptyRewardAddress } + stateDB.SetState(precompile.RewardManagerAddress, rewardAddressStorageKey, val.Hash()) + return nil } -// NewDisableRewardManagerConfig returns config for a network upgrade at [blockTimestamp] -// that disables RewardManager. -func NewDisableRewardManagerConfig(blockTimestamp *big.Int) *RewardManagerConfig { - return &RewardManagerConfig{ - UpgradeableConfig: precompile.UpgradeableConfig{ - BlockTimestamp: blockTimestamp, - Disable: true, - }, +// PackSetRewardAddress packs [addr] of type common.Address into the appropriate arguments for setRewardAddress. +// the packed bytes include selector (first 4 func signature bytes). +// This function is mostly used for tests. +func PackSetRewardAddress(addr common.Address) ([]byte, error) { + return RewardManagerABI.Pack("setRewardAddress", addr) +} + +// UnpackSetRewardAddressInput attempts to unpack [input] into the common.Address type argument +// assumes that [input] does not include selector (omits first 4 func signature bytes) +func UnpackSetRewardAddressInput(input []byte) (common.Address, error) { + res, err := RewardManagerABI.UnpackInput("setRewardAddress", input) + if err != nil { + return common.Address{}, err } + unpacked := *abi.ConvertType(res[0], new(common.Address)).(*common.Address) + return unpacked, nil } -// Equal returns true if [s] is a [*RewardManagerConfig] and it has been configured identical to [c]. -func (c *RewardManagerConfig) Equal(s precompile.StatefulPrecompileConfig) bool { - // typecast before comparison - other, ok := (s).(*RewardManagerConfig) - if !ok { - return false +func setRewardAddress(accessibleState precompile.PrecompileAccessibleState, caller common.Address, addr common.Address, input []byte, suppliedGas uint64, readOnly bool) (ret []byte, remainingGas uint64, err error) { + if remainingGas, err = precompile.DeductGas(suppliedGas, SetRewardAddressGasCost); err != nil { + return nil, 0, err + } + if readOnly { + return nil, remainingGas, vmerrs.ErrWriteProtection } - // modify this boolean accordingly with your custom RewardManagerConfig, to check if [other] and the current [c] are equal - // if RewardManagerConfig contains only UpgradeableConfig and precompile.AllowListConfig you can skip modifying it. - equals := c.UpgradeableConfig.Equal(&other.UpgradeableConfig) && c.AllowListConfig.Equal(&other.AllowListConfig) - if !equals { - return false + // attempts to unpack [input] into the arguments to the SetRewardAddressInput. + // Assumes that [input] does not include selector + // You can use unpacked [inputStruct] variable in your code + inputStruct, err := UnpackSetRewardAddressInput(input) + if err != nil { + return nil, remainingGas, err } - if c.InitialRewardConfig == nil { - return other.InitialRewardConfig == nil + // Allow list is enabled and SetRewardAddress is a state-changer function. + // This part of the code restricts the function to be called only by enabled/admin addresses in the allow list. + // You can modify/delete this code if you don't want this function to be restricted by the allow list. + stateDB := accessibleState.GetStateDB() + // Verify that the caller is in the allow list and therefore has the right to modify it + callerStatus := precompile.GetAllowListStatus(stateDB, precompile.RewardManagerAddress, caller) + if !callerStatus.IsEnabled() { + return nil, remainingGas, fmt.Errorf("%w: %s", ErrCannotSetRewardAddress, caller) } + // allow list code ends here. - return c.InitialRewardConfig.Equal(other.InitialRewardConfig) -} + if err := StoreRewardAddress(stateDB, inputStruct); err != nil { + return nil, remainingGas, err + } + // this function does not return an output, leave this one as is + packedOutput := []byte{} -// Address returns the address of the RewardManager. Addresses reside under the precompile/params.go -// Select a non-conflicting address and set it in the params.go. -func (c *RewardManagerConfig) Address() common.Address { - return precompile.RewardManagerAddress + // Return the packed output and the remaining gas + return packedOutput, remainingGas, nil } -// Configure configures [state] with the initial configuration. -func (c *RewardManagerConfig) Configure(chainConfig precompile.ChainConfig, state precompile.StateDB, _ precompile.BlockContext) error { - c.AllowListConfig.Configure(state, precompile.RewardManagerAddress) - // configure the RewardManager with the given initial configuration - if c.InitialRewardConfig != nil { - return c.InitialRewardConfig.Configure(state) - } else if chainConfig.AllowedFeeRecipients() { - // configure the RewardManager according to chainConfig - EnableAllowFeeRecipients(state) - } else { - // chainConfig does not have any reward address - // if chainConfig does not enable fee recipients - // default to disabling rewards - DisableFeeRewards(state) +func currentRewardAddress(accessibleState precompile.PrecompileAccessibleState, caller common.Address, addr common.Address, input []byte, suppliedGas uint64, readOnly bool) (ret []byte, remainingGas uint64, err error) { + if remainingGas, err = precompile.DeductGas(suppliedGas, CurrentRewardAddressGasCost); err != nil { + return nil, 0, err } - return nil + + // no input provided for this function + stateDB := accessibleState.GetStateDB() + output, _ := GetStoredRewardAddress(stateDB) + packedOutput, err := PackCurrentRewardAddressOutput(output) + if err != nil { + return nil, remainingGas, err + } + + // Return the packed output and the remaining gas + return packedOutput, remainingGas, nil } -// Contract returns the singleton stateful precompiled contract to be used for RewardManager. -func (c *RewardManagerConfig) Contract() precompile.StatefulPrecompiledContract { - return RewardManagerPrecompile +// PackDisableRewards packs the include selector (first 4 func signature bytes). +// This function is mostly used for tests. +func PackDisableRewards() ([]byte, error) { + return RewardManagerABI.Pack("disableRewards") } -func (c *RewardManagerConfig) Verify() error { - if err := c.AllowListConfig.Verify(); err != nil { - return err +func disableRewards(accessibleState precompile.PrecompileAccessibleState, caller common.Address, addr common.Address, input []byte, suppliedGas uint64, readOnly bool) (ret []byte, remainingGas uint64, err error) { + if remainingGas, err = precompile.DeductGas(suppliedGas, DisableRewardsGasCost); err != nil { + return nil, 0, err } - if c.InitialRewardConfig != nil { - return c.InitialRewardConfig.Verify() + if readOnly { + return nil, remainingGas, vmerrs.ErrWriteProtection } - return nil + // no input provided for this function + + // Allow list is enabled and DisableRewards is a state-changer function. + // This part of the code restricts the function to be called only by enabled/admin addresses in the allow list. + // You can modify/delete this code if you don't want this function to be restricted by the allow list. + stateDB := accessibleState.GetStateDB() + // Verify that the caller is in the allow list and therefore has the right to modify it + callerStatus := precompile.GetAllowListStatus(stateDB, precompile.RewardManagerAddress, caller) + if !callerStatus.IsEnabled() { + return nil, remainingGas, fmt.Errorf("%w: %s", ErrCannotDisableRewards, caller) + } + // allow list code ends here. + DisableFeeRewards(stateDB) + // this function does not return an output, leave this one as is + packedOutput := []byte{} + + // Return the packed output and the remaining gas + return packedOutput, remainingGas, nil } -// String returns a string representation of the RewardManagerConfig. -func (c *RewardManagerConfig) String() string { - bytes, _ := json.Marshal(c) - return string(bytes) +// createRewardManagerPrecompile returns a StatefulPrecompiledContract with getters and setters for the precompile. +// Access to the getters/setters is controlled by an allow list for [precompileAddr]. +func createRewardManagerPrecompile(precompileAddr common.Address) (precompile.StatefulPrecompiledContract, error) { + var functions []*precompile.StatefulPrecompileFunction + functions = append(functions, precompile.CreateAllowListFunctions(precompileAddr)...) + abiFunctionMap := map[string]precompile.RunStatefulPrecompileFunc{ + "allowFeeRecipients": allowFeeRecipients, + "areFeeRecipientsAllowed": areFeeRecipientsAllowed, + "currentRewardAddress": currentRewardAddress, + "disableRewards": disableRewards, + "setRewardAddress": setRewardAddress, + } + + for name, function := range abiFunctionMap { + method, ok := RewardManagerABI.Methods[name] + if !ok { + return nil, fmt.Errorf("given method (%s) does not exist in the ABI", name) + } + functions = append(functions, precompile.NewStatefulPrecompileFunction(method.ID, function)) + } + + // Construct the contract with no fallback function. + return precompile.NewStatefulPrecompileContract(nil, functions) } From b9f8486c61ce3dfb5227f630a9f97e291b9b88e6 Mon Sep 17 00:00:00 2001 From: Ceyhun Onur Date: Fri, 23 Dec 2022 17:19:03 +0300 Subject: [PATCH 10/23] fix abi path --- precompile/rewardmanager/contract.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/precompile/rewardmanager/contract.go b/precompile/rewardmanager/contract.go index 5287b16b2b..daabd7a0b3 100644 --- a/precompile/rewardmanager/contract.go +++ b/precompile/rewardmanager/contract.go @@ -43,7 +43,7 @@ var ( ErrEmptyRewardAddress = errors.New("reward address cannot be empty") // RewardManagerRawABI contains the raw ABI of RewardManager contract. - //go:embed reward_manager.abi + //go:embed contract.abi RewardManagerRawABI string RewardManagerABI abi.ABI // will be initialized by init function From af8899faf08656b3e74d862c9128939657290808 Mon Sep 17 00:00:00 2001 From: Ceyhun Onur Date: Fri, 23 Dec 2022 17:20:37 +0300 Subject: [PATCH 11/23] move typecheck --- precompile/rewardmanager/config.go | 2 ++ precompile/rewardmanager/contract.go | 2 -- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/precompile/rewardmanager/config.go b/precompile/rewardmanager/config.go index c5889d0e83..6b85f6fedb 100644 --- a/precompile/rewardmanager/config.go +++ b/precompile/rewardmanager/config.go @@ -14,6 +14,8 @@ import ( "github.com/ethereum/go-ethereum/common" ) +var _ precompile.StatefulPrecompileConfig = &RewardManagerConfig{} + type InitialRewardConfig struct { AllowFeeRecipients bool `json:"allowFeeRecipients"` RewardAddress common.Address `json:"rewardAddress,omitempty"` diff --git a/precompile/rewardmanager/contract.go b/precompile/rewardmanager/contract.go index daabd7a0b3..b7b13aba94 100644 --- a/precompile/rewardmanager/contract.go +++ b/precompile/rewardmanager/contract.go @@ -31,8 +31,6 @@ const ( // Singleton StatefulPrecompiledContract and signatures. var ( - _ precompile.StatefulPrecompileConfig = &RewardManagerConfig{} - ErrCannotAllowFeeRecipients = errors.New("non-enabled cannot call allowFeeRecipients") ErrCannotAreFeeRecipientsAllowed = errors.New("non-enabled cannot call areFeeRecipientsAllowed") ErrCannotCurrentRewardAddress = errors.New("non-enabled cannot call currentRewardAddress") From aab1239056cf1055fdd93a027c7cd55a9381979e Mon Sep 17 00:00:00 2001 From: Ceyhun Onur Date: Mon, 26 Dec 2022 21:17:29 +0300 Subject: [PATCH 12/23] move precompiles to their own packages --- core/blockchain_reader.go | 8 +- core/genesis_test.go | 7 +- core/state_processor_test.go | 4 +- core/state_transition.go | 5 +- core/stateful_precompile_test.go | 291 ++++++------- core/test_blockchain.go | 22 +- core/tx_pool.go | 5 +- core/vm/evm.go | 3 +- eth/gasprice/gasprice_test.go | 5 +- params/precompile_config.go | 25 +- params/precompile_config_test.go | 37 +- params/upgrade_config_test.go | 63 +-- plugin/evm/vm_test.go | 52 +-- plugin/evm/vm_upgrade_bytes_test.go | 10 +- precompile/allow_list.go | 6 +- precompile/config_test.go | 390 ------------------ precompile/contract.go | 60 +-- precompile/contract_native_minter.go | 227 ---------- .../config.go} | 42 +- precompile/deployerallowlist/config_test.go | 95 +++++ precompile/deployerallowlist/contract.go | 27 ++ precompile/feemanager/config.go | 109 +++++ precompile/feemanager/config_test.go | 128 ++++++ .../contract.go} | 169 ++------ precompile/interface.go | 61 +++ precompile/mock_interface.go | 115 ++++++ precompile/nativeminter/config.go | 125 ++++++ precompile/nativeminter/config_test.go | 150 +++++++ .../nativeminter/contract_native_minter.go | 116 ++++++ precompile/rewardmanager/config_test.go | 4 +- precompile/stateful_precompile_config.go | 4 +- .../config.go} | 43 +- precompile/txallowlist/config_test.go | 105 +++++ precompile/txallowlist/contract.go.go | 32 ++ precompile/utils.go | 10 +- tests/e2e/utils/evm_client.go | 4 +- 36 files changed, 1427 insertions(+), 1132 deletions(-) delete mode 100644 precompile/config_test.go delete mode 100644 precompile/contract_native_minter.go rename precompile/{contract_deployer_allow_list.go => deployerallowlist/config.go} (58%) create mode 100644 precompile/deployerallowlist/config_test.go create mode 100644 precompile/deployerallowlist/contract.go create mode 100644 precompile/feemanager/config.go create mode 100644 precompile/feemanager/config_test.go rename precompile/{fee_config_manager.go => feemanager/contract.go} (56%) create mode 100644 precompile/interface.go create mode 100644 precompile/mock_interface.go create mode 100644 precompile/nativeminter/config.go create mode 100644 precompile/nativeminter/config_test.go create mode 100644 precompile/nativeminter/contract_native_minter.go rename precompile/{tx_allow_list.go => txallowlist/config.go} (57%) create mode 100644 precompile/txallowlist/config_test.go create mode 100644 precompile/txallowlist/contract.go.go diff --git a/core/blockchain_reader.go b/core/blockchain_reader.go index 35be0d65c1..d2602b645a 100644 --- a/core/blockchain_reader.go +++ b/core/blockchain_reader.go @@ -40,6 +40,8 @@ import ( "github.com/ava-labs/subnet-evm/core/vm" "github.com/ava-labs/subnet-evm/params" "github.com/ava-labs/subnet-evm/precompile" + "github.com/ava-labs/subnet-evm/precompile/feemanager" + "github.com/ava-labs/subnet-evm/precompile/rewardmanager" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/event" ) @@ -366,7 +368,7 @@ func (bc *BlockChain) GetFeeConfigAt(parent *types.Header) (commontype.FeeConfig return commontype.EmptyFeeConfig, nil, err } - storedFeeConfig := precompile.GetStoredFeeConfig(stateDB) + storedFeeConfig := feemanager.GetStoredFeeConfig(stateDB) // this should not return an invalid fee config since it's assumed that // StoreFeeConfig returns an error when an invalid fee config is attempted to be stored. // However an external stateDB call can modify the contract state. @@ -374,7 +376,7 @@ func (bc *BlockChain) GetFeeConfigAt(parent *types.Header) (commontype.FeeConfig if err := storedFeeConfig.Verify(); err != nil { return commontype.EmptyFeeConfig, nil, err } - lastChangedAt := precompile.GetFeeConfigLastChangedAt(stateDB) + lastChangedAt := feemanager.GetFeeConfigLastChangedAt(stateDB) cacheable := &cacheableFeeConfig{feeConfig: storedFeeConfig, lastChangedAt: lastChangedAt} // add it to the cache bc.feeConfigCache.Add(parent.Root, cacheable) @@ -402,7 +404,7 @@ func (bc *BlockChain) GetCoinbaseAt(parent *types.Header) (common.Address, bool, if err != nil { return common.Address{}, false, err } - rewardAddress, feeRecipients := precompile.GetStoredRewardAddress(stateDB) + rewardAddress, feeRecipients := rewardmanager.GetStoredRewardAddress(stateDB) return rewardAddress, feeRecipients, nil } diff --git a/core/genesis_test.go b/core/genesis_test.go index 920e5337b6..c9d84ced6c 100644 --- a/core/genesis_test.go +++ b/core/genesis_test.go @@ -39,6 +39,7 @@ import ( "github.com/ava-labs/subnet-evm/ethdb" "github.com/ava-labs/subnet-evm/params" "github.com/ava-labs/subnet-evm/precompile" + "github.com/ava-labs/subnet-evm/precompile/deployerallowlist" "github.com/davecgh/go-spew/spew" "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/assert" @@ -190,11 +191,11 @@ func TestStatefulPrecompilesConfigure(t *testing.T) { "allow list enabled in genesis": { getConfig: func() *params.ChainConfig { config := *params.TestChainConfig - config.ContractDeployerAllowListConfig = precompile.NewContractDeployerAllowListConfig(big.NewInt(0), []common.Address{addr}, nil) + config.ContractDeployerAllowListConfig = deployerallowlist.NewContractDeployerAllowListConfig(big.NewInt(0), []common.Address{addr}, nil) return &config }, assertState: func(t *testing.T, sdb *state.StateDB) { - assert.Equal(t, precompile.AllowListAdmin, precompile.GetContractDeployerAllowListStatus(sdb, addr), "unexpected allow list status for modified address") + assert.Equal(t, precompile.AllowListAdmin, deployerallowlist.GetContractDeployerAllowListStatus(sdb, addr), "unexpected allow list status for modified address") assert.Equal(t, uint64(1), sdb.GetNonce(precompile.ContractDeployerAllowListAddress)) }, }, @@ -265,7 +266,7 @@ func TestPrecompileActivationAfterHeaderBlock(t *testing.T) { require.Greater(block.Time(), bc.lastAccepted.Time()) activatedGenesis := customg - contractDeployerConfig := precompile.NewContractDeployerAllowListConfig(big.NewInt(51), nil, nil) + contractDeployerConfig := deployerallowlist.NewContractDeployerAllowListConfig(big.NewInt(51), nil, nil) activatedGenesis.Config.UpgradeConfig.PrecompileUpgrades = []params.PrecompileUpgrade{ { // Enable ContractDeployerAllowList at timestamp 50 diff --git a/core/state_processor_test.go b/core/state_processor_test.go index 0c48cd5f4e..bfa0bdc062 100644 --- a/core/state_processor_test.go +++ b/core/state_processor_test.go @@ -36,7 +36,7 @@ import ( "github.com/ava-labs/subnet-evm/core/types" "github.com/ava-labs/subnet-evm/core/vm" "github.com/ava-labs/subnet-evm/params" - "github.com/ava-labs/subnet-evm/precompile" + "github.com/ava-labs/subnet-evm/precompile/txallowlist" "github.com/ava-labs/subnet-evm/trie" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" @@ -316,7 +316,7 @@ func TestBadTxAllowListBlock(t *testing.T) { SubnetEVMTimestamp: big.NewInt(0), }, PrecompileUpgrade: params.PrecompileUpgrade{ - TxAllowListConfig: precompile.NewTxAllowListConfig(big.NewInt(0), nil, nil), + TxAllowListConfig: txallowlist.NewTxAllowListConfig(big.NewInt(0), nil, nil), }, } signer = types.LatestSigner(config) diff --git a/core/state_transition.go b/core/state_transition.go index acd81569e2..5fcfa642b5 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -37,6 +37,7 @@ import ( "github.com/ava-labs/subnet-evm/core/vm" "github.com/ava-labs/subnet-evm/params" "github.com/ava-labs/subnet-evm/precompile" + "github.com/ava-labs/subnet-evm/precompile/txallowlist" "github.com/ava-labs/subnet-evm/vmerrs" "github.com/ethereum/go-ethereum/common" ) @@ -250,9 +251,9 @@ func (st *StateTransition) preCheck() error { // Check that the sender is on the tx allow list if enabled if st.evm.ChainConfig().IsPrecompileEnabled(precompile.TxAllowListAddress, st.evm.Context.Time) { - txAllowListRole := precompile.GetTxAllowListStatus(st.state, st.msg.From()) + txAllowListRole := txallowlist.GetTxAllowListStatus(st.state, st.msg.From()) if !txAllowListRole.IsEnabled() { - return fmt.Errorf("%w: %s", precompile.ErrSenderAddressNotAllowListed, st.msg.From()) + return fmt.Errorf("%w: %s", txallowlist.ErrSenderAddressNotAllowListed, st.msg.From()) } } } diff --git a/core/stateful_precompile_test.go b/core/stateful_precompile_test.go index 702c8715b4..b89c587fc8 100644 --- a/core/stateful_precompile_test.go +++ b/core/stateful_precompile_test.go @@ -14,12 +14,19 @@ import ( "github.com/ava-labs/subnet-evm/core/state" "github.com/ava-labs/subnet-evm/params" "github.com/ava-labs/subnet-evm/precompile" + "github.com/ava-labs/subnet-evm/precompile/deployerallowlist" + "github.com/ava-labs/subnet-evm/precompile/feemanager" + "github.com/ava-labs/subnet-evm/precompile/nativeminter" + "github.com/ava-labs/subnet-evm/precompile/rewardmanager" + "github.com/ava-labs/subnet-evm/precompile/txallowlist" "github.com/ava-labs/subnet-evm/vmerrs" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/math" "github.com/stretchr/testify/require" ) +// TODO: move this to precompile package once cross-import is resolved + var ( _ precompile.BlockContext = &mockBlockContext{} _ precompile.PrecompileAccessibleState = &mockAccessibleState{} @@ -95,7 +102,7 @@ func TestContractDeployerAllowListRun(t *testing.T) { readOnly: false, expectedRes: []byte{}, assertState: func(t *testing.T, state *state.StateDB) { - res := precompile.GetContractDeployerAllowListStatus(state, noRoleAddr) + res := deployerallowlist.GetContractDeployerAllowListStatus(state, noRoleAddr) require.Equal(t, precompile.AllowListAdmin, res) }, }, @@ -111,7 +118,7 @@ func TestContractDeployerAllowListRun(t *testing.T) { readOnly: false, expectedRes: []byte{}, assertState: func(t *testing.T, state *state.StateDB) { - res := precompile.GetContractDeployerAllowListStatus(state, noRoleAddr) + res := deployerallowlist.GetContractDeployerAllowListStatus(state, noRoleAddr) require.Equal(t, precompile.AllowListEnabled, res) }, }, @@ -127,7 +134,7 @@ func TestContractDeployerAllowListRun(t *testing.T) { readOnly: false, expectedRes: []byte{}, assertState: func(t *testing.T, state *state.StateDB) { - res := precompile.GetContractDeployerAllowListStatus(state, adminAddr) + res := deployerallowlist.GetContractDeployerAllowListStatus(state, adminAddr) require.Equal(t, precompile.AllowListNoRole, res) }, }, @@ -237,13 +244,13 @@ func TestContractDeployerAllowListRun(t *testing.T) { require.NoError(t, err) // Set up the state so that each address has the expected permissions at the start. - precompile.SetContractDeployerAllowListStatus(state, adminAddr, precompile.AllowListAdmin) - precompile.SetContractDeployerAllowListStatus(state, noRoleAddr, precompile.AllowListNoRole) - require.Equal(t, precompile.AllowListAdmin, precompile.GetContractDeployerAllowListStatus(state, adminAddr)) - require.Equal(t, precompile.AllowListNoRole, precompile.GetContractDeployerAllowListStatus(state, noRoleAddr)) + deployerallowlist.SetContractDeployerAllowListStatus(state, adminAddr, precompile.AllowListAdmin) + deployerallowlist.SetContractDeployerAllowListStatus(state, noRoleAddr, precompile.AllowListNoRole) + require.Equal(t, precompile.AllowListAdmin, deployerallowlist.GetContractDeployerAllowListStatus(state, adminAddr)) + require.Equal(t, precompile.AllowListNoRole, deployerallowlist.GetContractDeployerAllowListStatus(state, noRoleAddr)) blockContext := &mockBlockContext{blockNumber: common.Big0} - ret, remainingGas, err := precompile.ContractDeployerAllowListPrecompile.Run(&mockAccessibleState{state: state, blockContext: blockContext, snowContext: snow.DefaultContextTest()}, test.caller, precompile.ContractDeployerAllowListAddress, test.input(), test.suppliedGas, test.readOnly) + ret, remainingGas, err := deployerallowlist.ContractDeployerAllowListPrecompile.Run(&mockAccessibleState{state: state, blockContext: blockContext, snowContext: snow.DefaultContextTest()}, test.caller, precompile.ContractDeployerAllowListAddress, test.input(), test.suppliedGas, test.readOnly) if len(test.expectedErr) != 0 { require.ErrorContains(t, err, test.expectedErr) } else { @@ -290,7 +297,7 @@ func TestTxAllowListRun(t *testing.T) { readOnly: false, expectedRes: []byte{}, assertState: func(t *testing.T, state *state.StateDB) { - res := precompile.GetTxAllowListStatus(state, noRoleAddr) + res := txallowlist.GetTxAllowListStatus(state, noRoleAddr) require.Equal(t, precompile.AllowListAdmin, res) }, }, @@ -306,7 +313,7 @@ func TestTxAllowListRun(t *testing.T) { readOnly: false, expectedRes: []byte{}, assertState: func(t *testing.T, state *state.StateDB) { - res := precompile.GetTxAllowListStatus(state, noRoleAddr) + res := txallowlist.GetTxAllowListStatus(state, noRoleAddr) require.Equal(t, precompile.AllowListEnabled, res) }, }, @@ -322,7 +329,7 @@ func TestTxAllowListRun(t *testing.T) { readOnly: false, expectedRes: []byte{}, assertState: func(t *testing.T, state *state.StateDB) { - res := precompile.GetTxAllowListStatus(state, adminAddr) + res := txallowlist.GetTxAllowListStatus(state, adminAddr) require.Equal(t, precompile.AllowListNoRole, res) }, }, @@ -433,11 +440,11 @@ func TestTxAllowListRun(t *testing.T) { require.NoError(t, err) // Set up the state so that each address has the expected permissions at the start. - precompile.SetTxAllowListStatus(state, adminAddr, precompile.AllowListAdmin) - require.Equal(t, precompile.AllowListAdmin, precompile.GetTxAllowListStatus(state, adminAddr)) + txallowlist.SetTxAllowListStatus(state, adminAddr, precompile.AllowListAdmin) + require.Equal(t, precompile.AllowListAdmin, txallowlist.GetTxAllowListStatus(state, adminAddr)) blockContext := &mockBlockContext{blockNumber: common.Big0} - ret, remainingGas, err := precompile.TxAllowListPrecompile.Run(&mockAccessibleState{state: state, blockContext: blockContext, snowContext: snow.DefaultContextTest()}, test.caller, precompile.TxAllowListAddress, test.input(), test.suppliedGas, test.readOnly) + ret, remainingGas, err := txallowlist.TxAllowListPrecompile.Run(&mockAccessibleState{state: state, blockContext: blockContext, snowContext: snow.DefaultContextTest()}, test.caller, precompile.TxAllowListAddress, test.input(), test.suppliedGas, test.readOnly) if len(test.expectedErr) != 0 { require.ErrorContains(t, err, test.expectedErr) } else { @@ -460,7 +467,7 @@ func TestContractNativeMinterRun(t *testing.T) { input func() []byte suppliedGas uint64 readOnly bool - config *precompile.ContractNativeMinterConfig + config *nativeminter.ContractNativeMinterConfig expectedRes []byte expectedErr string @@ -477,24 +484,24 @@ func TestContractNativeMinterRun(t *testing.T) { "mint funds from no role fails": { caller: noRoleAddr, input: func() []byte { - input, err := precompile.PackMintInput(noRoleAddr, common.Big1) + input, err := nativeminter.PackMintInput(noRoleAddr, common.Big1) require.NoError(t, err) return input }, - suppliedGas: precompile.MintGasCost, + suppliedGas: nativeminter.MintGasCost, readOnly: false, - expectedErr: precompile.ErrCannotMint.Error(), + expectedErr: nativeminter.ErrCannotMint.Error(), }, "mint funds from enabled address": { caller: enabledAddr, input: func() []byte { - input, err := precompile.PackMintInput(enabledAddr, common.Big1) + input, err := nativeminter.PackMintInput(enabledAddr, common.Big1) require.NoError(t, err) return input }, - suppliedGas: precompile.MintGasCost, + suppliedGas: nativeminter.MintGasCost, readOnly: false, expectedRes: []byte{}, assertState: func(t *testing.T, state *state.StateDB) { @@ -510,15 +517,15 @@ func TestContractNativeMinterRun(t *testing.T) { readOnly: false, expectedRes: common.Hash(precompile.AllowListEnabled).Bytes(), assertState: func(t *testing.T, state *state.StateDB) { - require.Equal(t, precompile.AllowListEnabled, precompile.GetContractNativeMinterStatus(state, testAddr)) + require.Equal(t, precompile.AllowListEnabled, nativeminter.GetContractNativeMinterStatus(state, testAddr)) }, - config: &precompile.ContractNativeMinterConfig{ + config: &nativeminter.ContractNativeMinterConfig{ AllowListConfig: precompile.AllowListConfig{EnabledAddresses: []common.Address{testAddr}}, }, }, "initial mint funds": { caller: enabledAddr, - config: &precompile.ContractNativeMinterConfig{ + config: &nativeminter.ContractNativeMinterConfig{ InitialMint: map[common.Address]*math.HexOrDecimal256{ enabledAddr: math.NewHexOrDecimal256(2), }, @@ -536,12 +543,12 @@ func TestContractNativeMinterRun(t *testing.T) { "mint funds from admin address": { caller: adminAddr, input: func() []byte { - input, err := precompile.PackMintInput(adminAddr, common.Big1) + input, err := nativeminter.PackMintInput(adminAddr, common.Big1) require.NoError(t, err) return input }, - suppliedGas: precompile.MintGasCost, + suppliedGas: nativeminter.MintGasCost, readOnly: false, expectedRes: []byte{}, assertState: func(t *testing.T, state *state.StateDB) { @@ -551,12 +558,12 @@ func TestContractNativeMinterRun(t *testing.T) { "mint max big funds": { caller: adminAddr, input: func() []byte { - input, err := precompile.PackMintInput(adminAddr, math.MaxBig256) + input, err := nativeminter.PackMintInput(adminAddr, math.MaxBig256) require.NoError(t, err) return input }, - suppliedGas: precompile.MintGasCost, + suppliedGas: nativeminter.MintGasCost, readOnly: false, expectedRes: []byte{}, assertState: func(t *testing.T, state *state.StateDB) { @@ -566,48 +573,48 @@ func TestContractNativeMinterRun(t *testing.T) { "readOnly mint with noRole fails": { caller: noRoleAddr, input: func() []byte { - input, err := precompile.PackMintInput(adminAddr, common.Big1) + input, err := nativeminter.PackMintInput(adminAddr, common.Big1) require.NoError(t, err) return input }, - suppliedGas: precompile.MintGasCost, + suppliedGas: nativeminter.MintGasCost, readOnly: true, expectedErr: vmerrs.ErrWriteProtection.Error(), }, "readOnly mint with allow role fails": { caller: enabledAddr, input: func() []byte { - input, err := precompile.PackMintInput(enabledAddr, common.Big1) + input, err := nativeminter.PackMintInput(enabledAddr, common.Big1) require.NoError(t, err) return input }, - suppliedGas: precompile.MintGasCost, + suppliedGas: nativeminter.MintGasCost, readOnly: true, expectedErr: vmerrs.ErrWriteProtection.Error(), }, "readOnly mint with admin role fails": { caller: adminAddr, input: func() []byte { - input, err := precompile.PackMintInput(adminAddr, common.Big1) + input, err := nativeminter.PackMintInput(adminAddr, common.Big1) require.NoError(t, err) return input }, - suppliedGas: precompile.MintGasCost, + suppliedGas: nativeminter.MintGasCost, readOnly: true, expectedErr: vmerrs.ErrWriteProtection.Error(), }, "insufficient gas mint from admin": { caller: adminAddr, input: func() []byte { - input, err := precompile.PackMintInput(enabledAddr, common.Big1) + input, err := nativeminter.PackMintInput(enabledAddr, common.Big1) require.NoError(t, err) return input }, - suppliedGas: precompile.MintGasCost - 1, + suppliedGas: nativeminter.MintGasCost - 1, readOnly: false, expectedErr: vmerrs.ErrOutOfGas.Error(), }, @@ -652,7 +659,7 @@ func TestContractNativeMinterRun(t *testing.T) { readOnly: false, expectedRes: []byte{}, assertState: func(t *testing.T, state *state.StateDB) { - res := precompile.GetContractNativeMinterStatus(state, noRoleAddr) + res := nativeminter.GetContractNativeMinterStatus(state, noRoleAddr) require.Equal(t, precompile.AllowListEnabled, res) }, }, @@ -675,18 +682,18 @@ func TestContractNativeMinterRun(t *testing.T) { require.NoError(t, err) // Set up the state so that each address has the expected permissions at the start. - precompile.SetContractNativeMinterStatus(state, adminAddr, precompile.AllowListAdmin) - precompile.SetContractNativeMinterStatus(state, enabledAddr, precompile.AllowListEnabled) - precompile.SetContractNativeMinterStatus(state, noRoleAddr, precompile.AllowListNoRole) - require.Equal(t, precompile.AllowListAdmin, precompile.GetContractNativeMinterStatus(state, adminAddr)) - require.Equal(t, precompile.AllowListEnabled, precompile.GetContractNativeMinterStatus(state, enabledAddr)) - require.Equal(t, precompile.AllowListNoRole, precompile.GetContractNativeMinterStatus(state, noRoleAddr)) + nativeminter.SetContractNativeMinterStatus(state, adminAddr, precompile.AllowListAdmin) + nativeminter.SetContractNativeMinterStatus(state, enabledAddr, precompile.AllowListEnabled) + nativeminter.SetContractNativeMinterStatus(state, noRoleAddr, precompile.AllowListNoRole) + require.Equal(t, precompile.AllowListAdmin, nativeminter.GetContractNativeMinterStatus(state, adminAddr)) + require.Equal(t, precompile.AllowListEnabled, nativeminter.GetContractNativeMinterStatus(state, enabledAddr)) + require.Equal(t, precompile.AllowListNoRole, nativeminter.GetContractNativeMinterStatus(state, noRoleAddr)) blockContext := &mockBlockContext{blockNumber: common.Big0} if test.config != nil { test.config.Configure(params.TestChainConfig, state, blockContext) } - ret, remainingGas, err := precompile.ContractNativeMinterPrecompile.Run(&mockAccessibleState{state: state, blockContext: blockContext, snowContext: snow.DefaultContextTest()}, test.caller, precompile.ContractNativeMinterAddress, test.input(), test.suppliedGas, test.readOnly) + ret, remainingGas, err := nativeminter.ContractNativeMinterPrecompile.Run(&mockAccessibleState{state: state, blockContext: blockContext, snowContext: snow.DefaultContextTest()}, test.caller, precompile.ContractNativeMinterAddress, test.input(), test.suppliedGas, test.readOnly) if len(test.expectedErr) != 0 { require.ErrorContains(t, err, test.expectedErr) } else { @@ -710,7 +717,7 @@ func TestFeeConfigManagerRun(t *testing.T) { input func() []byte suppliedGas uint64 readOnly bool - config *precompile.FeeConfigManagerConfig + config *feemanager.FeeConfigManagerConfig expectedRes []byte expectedErr string @@ -726,28 +733,28 @@ func TestFeeConfigManagerRun(t *testing.T) { "set config from no role fails": { caller: noRoleAddr, input: func() []byte { - input, err := precompile.PackSetFeeConfig(testFeeConfig) + input, err := feemanager.PackSetFeeConfig(testFeeConfig) require.NoError(t, err) return input }, - suppliedGas: precompile.SetFeeConfigGasCost, + suppliedGas: feemanager.SetFeeConfigGasCost, readOnly: false, - expectedErr: precompile.ErrCannotChangeFee.Error(), + expectedErr: feemanager.ErrCannotChangeFee.Error(), }, "set config from enabled address": { caller: enabledAddr, input: func() []byte { - input, err := precompile.PackSetFeeConfig(testFeeConfig) + input, err := feemanager.PackSetFeeConfig(testFeeConfig) require.NoError(t, err) return input }, - suppliedGas: precompile.SetFeeConfigGasCost, + suppliedGas: feemanager.SetFeeConfigGasCost, readOnly: false, expectedRes: []byte{}, assertState: func(t *testing.T, state *state.StateDB) { - feeConfig := precompile.GetStoredFeeConfig(state) + feeConfig := feemanager.GetStoredFeeConfig(state) require.Equal(t, testFeeConfig, feeConfig) }, }, @@ -756,60 +763,60 @@ func TestFeeConfigManagerRun(t *testing.T) { input: func() []byte { feeConfig := testFeeConfig feeConfig.MinBlockGasCost = new(big.Int).Mul(feeConfig.MaxBlockGasCost, common.Big2) - input, err := precompile.PackSetFeeConfig(feeConfig) + input, err := feemanager.PackSetFeeConfig(feeConfig) require.NoError(t, err) return input }, - suppliedGas: precompile.SetFeeConfigGasCost, + suppliedGas: feemanager.SetFeeConfigGasCost, readOnly: false, expectedRes: nil, - config: &precompile.FeeConfigManagerConfig{ + config: &feemanager.FeeConfigManagerConfig{ InitialFeeConfig: &testFeeConfig, }, expectedErr: "cannot be greater than maxBlockGasCost", assertState: func(t *testing.T, state *state.StateDB) { - feeConfig := precompile.GetStoredFeeConfig(state) + feeConfig := feemanager.GetStoredFeeConfig(state) require.Equal(t, testFeeConfig, feeConfig) }, }, "set config from admin address": { caller: adminAddr, input: func() []byte { - input, err := precompile.PackSetFeeConfig(testFeeConfig) + input, err := feemanager.PackSetFeeConfig(testFeeConfig) require.NoError(t, err) return input }, - suppliedGas: precompile.SetFeeConfigGasCost, + suppliedGas: feemanager.SetFeeConfigGasCost, readOnly: false, expectedRes: []byte{}, assertState: func(t *testing.T, state *state.StateDB) { - feeConfig := precompile.GetStoredFeeConfig(state) + feeConfig := feemanager.GetStoredFeeConfig(state) require.Equal(t, testFeeConfig, feeConfig) - lastChangedAt := precompile.GetFeeConfigLastChangedAt(state) + lastChangedAt := feemanager.GetFeeConfigLastChangedAt(state) require.EqualValues(t, testBlockNumber, lastChangedAt) }, }, "get fee config from non-enabled address": { caller: noRoleAddr, preCondition: func(t *testing.T, state *state.StateDB) { - err := precompile.StoreFeeConfig(state, testFeeConfig, &mockBlockContext{blockNumber: big.NewInt(6)}) + err := feemanager.StoreFeeConfig(state, testFeeConfig, &mockBlockContext{blockNumber: big.NewInt(6)}) require.NoError(t, err) }, input: func() []byte { - return precompile.PackGetFeeConfigInput() + return feemanager.PackGetFeeConfigInput() }, - suppliedGas: precompile.GetFeeConfigGasCost, + suppliedGas: feemanager.GetFeeConfigGasCost, readOnly: true, expectedRes: func() []byte { - res, err := precompile.PackFeeConfig(testFeeConfig) + res, err := feemanager.PackFeeConfig(testFeeConfig) require.NoError(t, err) return res }(), assertState: func(t *testing.T, state *state.StateDB) { - feeConfig := precompile.GetStoredFeeConfig(state) - lastChangedAt := precompile.GetFeeConfigLastChangedAt(state) + feeConfig := feemanager.GetStoredFeeConfig(state) + lastChangedAt := feemanager.GetFeeConfigLastChangedAt(state) require.Equal(t, testFeeConfig, feeConfig) require.EqualValues(t, big.NewInt(6), lastChangedAt) }, @@ -817,21 +824,21 @@ func TestFeeConfigManagerRun(t *testing.T) { "get initial fee config": { caller: noRoleAddr, input: func() []byte { - return precompile.PackGetFeeConfigInput() + return feemanager.PackGetFeeConfigInput() }, - suppliedGas: precompile.GetFeeConfigGasCost, - config: &precompile.FeeConfigManagerConfig{ + suppliedGas: feemanager.GetFeeConfigGasCost, + config: &feemanager.FeeConfigManagerConfig{ InitialFeeConfig: &testFeeConfig, }, readOnly: true, expectedRes: func() []byte { - res, err := precompile.PackFeeConfig(testFeeConfig) + res, err := feemanager.PackFeeConfig(testFeeConfig) require.NoError(t, err) return res }(), assertState: func(t *testing.T, state *state.StateDB) { - feeConfig := precompile.GetStoredFeeConfig(state) - lastChangedAt := precompile.GetFeeConfigLastChangedAt(state) + feeConfig := feemanager.GetStoredFeeConfig(state) + lastChangedAt := feemanager.GetFeeConfigLastChangedAt(state) require.Equal(t, testFeeConfig, feeConfig) require.EqualValues(t, testBlockNumber, lastChangedAt) }, @@ -839,18 +846,18 @@ func TestFeeConfigManagerRun(t *testing.T) { "get last changed at from non-enabled address": { caller: noRoleAddr, preCondition: func(t *testing.T, state *state.StateDB) { - err := precompile.StoreFeeConfig(state, testFeeConfig, &mockBlockContext{blockNumber: testBlockNumber}) + err := feemanager.StoreFeeConfig(state, testFeeConfig, &mockBlockContext{blockNumber: testBlockNumber}) require.NoError(t, err) }, input: func() []byte { - return precompile.PackGetLastChangedAtInput() + return feemanager.PackGetLastChangedAtInput() }, - suppliedGas: precompile.GetLastChangedAtGasCost, + suppliedGas: feemanager.GetLastChangedAtGasCost, readOnly: true, expectedRes: common.BigToHash(testBlockNumber).Bytes(), assertState: func(t *testing.T, state *state.StateDB) { - feeConfig := precompile.GetStoredFeeConfig(state) - lastChangedAt := precompile.GetFeeConfigLastChangedAt(state) + feeConfig := feemanager.GetStoredFeeConfig(state) + lastChangedAt := feemanager.GetFeeConfigLastChangedAt(state) require.Equal(t, testFeeConfig, feeConfig) require.Equal(t, testBlockNumber, lastChangedAt) }, @@ -858,48 +865,48 @@ func TestFeeConfigManagerRun(t *testing.T) { "readOnly setFeeConfig with noRole fails": { caller: noRoleAddr, input: func() []byte { - input, err := precompile.PackSetFeeConfig(testFeeConfig) + input, err := feemanager.PackSetFeeConfig(testFeeConfig) require.NoError(t, err) return input }, - suppliedGas: precompile.SetFeeConfigGasCost, + suppliedGas: feemanager.SetFeeConfigGasCost, readOnly: true, expectedErr: vmerrs.ErrWriteProtection.Error(), }, "readOnly setFeeConfig with allow role fails": { caller: enabledAddr, input: func() []byte { - input, err := precompile.PackSetFeeConfig(testFeeConfig) + input, err := feemanager.PackSetFeeConfig(testFeeConfig) require.NoError(t, err) return input }, - suppliedGas: precompile.SetFeeConfigGasCost, + suppliedGas: feemanager.SetFeeConfigGasCost, readOnly: true, expectedErr: vmerrs.ErrWriteProtection.Error(), }, "readOnly setFeeConfig with admin role fails": { caller: adminAddr, input: func() []byte { - input, err := precompile.PackSetFeeConfig(testFeeConfig) + input, err := feemanager.PackSetFeeConfig(testFeeConfig) require.NoError(t, err) return input }, - suppliedGas: precompile.SetFeeConfigGasCost, + suppliedGas: feemanager.SetFeeConfigGasCost, readOnly: true, expectedErr: vmerrs.ErrWriteProtection.Error(), }, "insufficient gas setFeeConfig from admin": { caller: adminAddr, input: func() []byte { - input, err := precompile.PackSetFeeConfig(testFeeConfig) + input, err := feemanager.PackSetFeeConfig(testFeeConfig) require.NoError(t, err) return input }, - suppliedGas: precompile.SetFeeConfigGasCost - 1, + suppliedGas: feemanager.SetFeeConfigGasCost - 1, readOnly: false, expectedErr: vmerrs.ErrOutOfGas.Error(), }, @@ -915,7 +922,7 @@ func TestFeeConfigManagerRun(t *testing.T) { readOnly: false, expectedRes: []byte{}, assertState: func(t *testing.T, state *state.StateDB) { - res := precompile.GetFeeConfigManagerStatus(state, noRoleAddr) + res := feemanager.GetFeeConfigManagerStatus(state, noRoleAddr) require.Equal(t, precompile.AllowListEnabled, res) }, }, @@ -938,9 +945,9 @@ func TestFeeConfigManagerRun(t *testing.T) { require.NoError(t, err) // Set up the state so that each address has the expected permissions at the start. - precompile.SetFeeConfigManagerStatus(state, adminAddr, precompile.AllowListAdmin) - precompile.SetFeeConfigManagerStatus(state, enabledAddr, precompile.AllowListEnabled) - precompile.SetFeeConfigManagerStatus(state, noRoleAddr, precompile.AllowListNoRole) + feemanager.SetFeeConfigManagerStatus(state, adminAddr, precompile.AllowListAdmin) + feemanager.SetFeeConfigManagerStatus(state, enabledAddr, precompile.AllowListEnabled) + feemanager.SetFeeConfigManagerStatus(state, noRoleAddr, precompile.AllowListNoRole) if test.preCondition != nil { test.preCondition(t, state) @@ -950,7 +957,7 @@ func TestFeeConfigManagerRun(t *testing.T) { if test.config != nil { test.config.Configure(params.TestChainConfig, state, blockContext) } - ret, remainingGas, err := precompile.FeeConfigManagerPrecompile.Run(&mockAccessibleState{state: state, blockContext: blockContext, snowContext: snow.DefaultContextTest()}, test.caller, precompile.FeeConfigManagerAddress, test.input(), test.suppliedGas, test.readOnly) + ret, remainingGas, err := feemanager.FeeConfigManagerPrecompile.Run(&mockAccessibleState{state: state, blockContext: blockContext, snowContext: snow.DefaultContextTest()}, test.caller, precompile.FeeConfigManagerAddress, test.input(), test.suppliedGas, test.readOnly) if len(test.expectedErr) != 0 { require.ErrorContains(t, err, test.expectedErr) } else { @@ -974,7 +981,7 @@ func TestRewardManagerRun(t *testing.T) { input func() []byte suppliedGas uint64 readOnly bool - config *precompile.RewardManagerConfig + config *rewardmanager.RewardManagerConfig expectedRes []byte expectedErr string @@ -991,68 +998,68 @@ func TestRewardManagerRun(t *testing.T) { "set allow fee recipients from no role fails": { caller: noRoleAddr, input: func() []byte { - input, err := precompile.PackAllowFeeRecipients() + input, err := rewardmanager.PackAllowFeeRecipients() require.NoError(t, err) return input }, - suppliedGas: precompile.AllowFeeRecipientsGasCost, + suppliedGas: rewardmanager.AllowFeeRecipientsGasCost, readOnly: false, - expectedErr: precompile.ErrCannotAllowFeeRecipients.Error(), + expectedErr: rewardmanager.ErrCannotAllowFeeRecipients.Error(), }, "set reward address from no role fails": { caller: noRoleAddr, input: func() []byte { - input, err := precompile.PackSetRewardAddress(testAddr) + input, err := rewardmanager.PackSetRewardAddress(testAddr) require.NoError(t, err) return input }, - suppliedGas: precompile.SetRewardAddressGasCost, + suppliedGas: rewardmanager.SetRewardAddressGasCost, readOnly: false, - expectedErr: precompile.ErrCannotSetRewardAddress.Error(), + expectedErr: rewardmanager.ErrCannotSetRewardAddress.Error(), }, "disable rewards from no role fails": { caller: noRoleAddr, input: func() []byte { - input, err := precompile.PackDisableRewards() + input, err := rewardmanager.PackDisableRewards() require.NoError(t, err) return input }, - suppliedGas: precompile.DisableRewardsGasCost, + suppliedGas: rewardmanager.DisableRewardsGasCost, readOnly: false, - expectedErr: precompile.ErrCannotDisableRewards.Error(), + expectedErr: rewardmanager.ErrCannotDisableRewards.Error(), }, "set allow fee recipients from enabled succeeds": { caller: enabledAddr, input: func() []byte { - input, err := precompile.PackAllowFeeRecipients() + input, err := rewardmanager.PackAllowFeeRecipients() require.NoError(t, err) return input }, - suppliedGas: precompile.AllowFeeRecipientsGasCost, + suppliedGas: rewardmanager.AllowFeeRecipientsGasCost, readOnly: false, expectedRes: []byte{}, assertState: func(t *testing.T, state *state.StateDB) { - _, isFeeRecipients := precompile.GetStoredRewardAddress(state) + _, isFeeRecipients := rewardmanager.GetStoredRewardAddress(state) require.True(t, isFeeRecipients) }, }, "set reward address from enabled succeeds": { caller: enabledAddr, input: func() []byte { - input, err := precompile.PackSetRewardAddress(testAddr) + input, err := rewardmanager.PackSetRewardAddress(testAddr) require.NoError(t, err) return input }, - suppliedGas: precompile.SetRewardAddressGasCost, + suppliedGas: rewardmanager.SetRewardAddressGasCost, readOnly: false, expectedRes: []byte{}, assertState: func(t *testing.T, state *state.StateDB) { - address, isFeeRecipients := precompile.GetStoredRewardAddress(state) + address, isFeeRecipients := rewardmanager.GetStoredRewardAddress(state) require.Equal(t, testAddr, address) require.False(t, isFeeRecipients) }, @@ -1060,16 +1067,16 @@ func TestRewardManagerRun(t *testing.T) { "disable rewards from enabled succeeds": { caller: enabledAddr, input: func() []byte { - input, err := precompile.PackDisableRewards() + input, err := rewardmanager.PackDisableRewards() require.NoError(t, err) return input }, - suppliedGas: precompile.DisableRewardsGasCost, + suppliedGas: rewardmanager.DisableRewardsGasCost, readOnly: false, expectedRes: []byte{}, assertState: func(t *testing.T, state *state.StateDB) { - address, isFeeRecipients := precompile.GetStoredRewardAddress(state) + address, isFeeRecipients := rewardmanager.GetStoredRewardAddress(state) require.False(t, isFeeRecipients) require.Equal(t, constants.BlackholeAddr, address) }, @@ -1077,18 +1084,18 @@ func TestRewardManagerRun(t *testing.T) { "get current reward address from no role succeeds": { caller: noRoleAddr, preCondition: func(t *testing.T, state *state.StateDB) { - precompile.StoreRewardAddress(state, testAddr) + rewardmanager.StoreRewardAddress(state, testAddr) }, input: func() []byte { - input, err := precompile.PackCurrentRewardAddress() + input, err := rewardmanager.PackCurrentRewardAddress() require.NoError(t, err) return input }, - suppliedGas: precompile.CurrentRewardAddressGasCost, + suppliedGas: rewardmanager.CurrentRewardAddressGasCost, readOnly: false, expectedRes: func() []byte { - res, err := precompile.PackCurrentRewardAddressOutput(testAddr) + res, err := rewardmanager.PackCurrentRewardAddressOutput(testAddr) require.NoError(t, err) return res }(), @@ -1096,17 +1103,17 @@ func TestRewardManagerRun(t *testing.T) { "get are fee recipients allowed from no role succeeds": { caller: noRoleAddr, preCondition: func(t *testing.T, state *state.StateDB) { - precompile.EnableAllowFeeRecipients(state) + rewardmanager.EnableAllowFeeRecipients(state) }, input: func() []byte { - input, err := precompile.PackAreFeeRecipientsAllowed() + input, err := rewardmanager.PackAreFeeRecipientsAllowed() require.NoError(t, err) return input }, - suppliedGas: precompile.AreFeeRecipientsAllowedGasCost, + suppliedGas: rewardmanager.AreFeeRecipientsAllowedGasCost, readOnly: false, expectedRes: func() []byte { - res, err := precompile.PackAreFeeRecipientsAllowedOutput(true) + res, err := rewardmanager.PackAreFeeRecipientsAllowedOutput(true) require.NoError(t, err) return res }(), @@ -1114,19 +1121,19 @@ func TestRewardManagerRun(t *testing.T) { "get initial config with address": { caller: noRoleAddr, input: func() []byte { - input, err := precompile.PackCurrentRewardAddress() + input, err := rewardmanager.PackCurrentRewardAddress() require.NoError(t, err) return input }, - suppliedGas: precompile.CurrentRewardAddressGasCost, - config: &precompile.RewardManagerConfig{ - InitialRewardConfig: &precompile.InitialRewardConfig{ + suppliedGas: rewardmanager.CurrentRewardAddressGasCost, + config: &rewardmanager.RewardManagerConfig{ + InitialRewardConfig: &rewardmanager.InitialRewardConfig{ RewardAddress: testAddr, }, }, readOnly: false, expectedRes: func() []byte { - res, err := precompile.PackCurrentRewardAddressOutput(testAddr) + res, err := rewardmanager.PackCurrentRewardAddressOutput(testAddr) require.NoError(t, err) return res }(), @@ -1134,19 +1141,19 @@ func TestRewardManagerRun(t *testing.T) { "get initial config with allow fee recipients enabled": { caller: noRoleAddr, input: func() []byte { - input, err := precompile.PackAreFeeRecipientsAllowed() + input, err := rewardmanager.PackAreFeeRecipientsAllowed() require.NoError(t, err) return input }, - suppliedGas: precompile.AreFeeRecipientsAllowedGasCost, - config: &precompile.RewardManagerConfig{ - InitialRewardConfig: &precompile.InitialRewardConfig{ + suppliedGas: rewardmanager.AreFeeRecipientsAllowedGasCost, + config: &rewardmanager.RewardManagerConfig{ + InitialRewardConfig: &rewardmanager.InitialRewardConfig{ AllowFeeRecipients: true, }, }, readOnly: false, expectedRes: func() []byte { - res, err := precompile.PackAreFeeRecipientsAllowedOutput(true) + res, err := rewardmanager.PackAreFeeRecipientsAllowedOutput(true) require.NoError(t, err) return res }(), @@ -1154,72 +1161,72 @@ func TestRewardManagerRun(t *testing.T) { "readOnly allow fee recipients with allowed role fails": { caller: enabledAddr, input: func() []byte { - input, err := precompile.PackAllowFeeRecipients() + input, err := rewardmanager.PackAllowFeeRecipients() require.NoError(t, err) return input }, - suppliedGas: precompile.AllowFeeRecipientsGasCost, + suppliedGas: rewardmanager.AllowFeeRecipientsGasCost, readOnly: true, expectedErr: vmerrs.ErrWriteProtection.Error(), }, "readOnly set reward addresss with allowed role fails": { caller: enabledAddr, input: func() []byte { - input, err := precompile.PackSetRewardAddress(testAddr) + input, err := rewardmanager.PackSetRewardAddress(testAddr) require.NoError(t, err) return input }, - suppliedGas: precompile.SetRewardAddressGasCost, + suppliedGas: rewardmanager.SetRewardAddressGasCost, readOnly: true, expectedErr: vmerrs.ErrWriteProtection.Error(), }, "insufficient gas set reward address from allowed role": { caller: enabledAddr, input: func() []byte { - input, err := precompile.PackSetRewardAddress(testAddr) + input, err := rewardmanager.PackSetRewardAddress(testAddr) require.NoError(t, err) return input }, - suppliedGas: precompile.SetRewardAddressGasCost - 1, + suppliedGas: rewardmanager.SetRewardAddressGasCost - 1, readOnly: false, expectedErr: vmerrs.ErrOutOfGas.Error(), }, "insufficient gas allow fee recipients from allowed role": { caller: enabledAddr, input: func() []byte { - input, err := precompile.PackAllowFeeRecipients() + input, err := rewardmanager.PackAllowFeeRecipients() require.NoError(t, err) return input }, - suppliedGas: precompile.AllowFeeRecipientsGasCost - 1, + suppliedGas: rewardmanager.AllowFeeRecipientsGasCost - 1, readOnly: false, expectedErr: vmerrs.ErrOutOfGas.Error(), }, "insufficient gas read current reward address from allowed role": { caller: enabledAddr, input: func() []byte { - input, err := precompile.PackCurrentRewardAddress() + input, err := rewardmanager.PackCurrentRewardAddress() require.NoError(t, err) return input }, - suppliedGas: precompile.CurrentRewardAddressGasCost - 1, + suppliedGas: rewardmanager.CurrentRewardAddressGasCost - 1, readOnly: false, expectedErr: vmerrs.ErrOutOfGas.Error(), }, "insufficient gas are fee recipients allowed from allowed role": { caller: enabledAddr, input: func() []byte { - input, err := precompile.PackAreFeeRecipientsAllowed() + input, err := rewardmanager.PackAreFeeRecipientsAllowed() require.NoError(t, err) return input }, - suppliedGas: precompile.AreFeeRecipientsAllowedGasCost - 1, + suppliedGas: rewardmanager.AreFeeRecipientsAllowedGasCost - 1, readOnly: false, expectedErr: vmerrs.ErrOutOfGas.Error(), }, @@ -1235,7 +1242,7 @@ func TestRewardManagerRun(t *testing.T) { readOnly: false, expectedRes: []byte{}, assertState: func(t *testing.T, state *state.StateDB) { - res := precompile.GetRewardManagerAllowListStatus(state, noRoleAddr) + res := rewardmanager.GetRewardManagerAllowListStatus(state, noRoleAddr) require.Equal(t, precompile.AllowListEnabled, res) }, }, @@ -1258,9 +1265,9 @@ func TestRewardManagerRun(t *testing.T) { require.NoError(t, err) // Set up the state so that each address has the expected permissions at the start. - precompile.SetRewardManagerAllowListStatus(state, adminAddr, precompile.AllowListAdmin) - precompile.SetRewardManagerAllowListStatus(state, enabledAddr, precompile.AllowListEnabled) - precompile.SetRewardManagerAllowListStatus(state, noRoleAddr, precompile.AllowListNoRole) + rewardmanager.SetRewardManagerAllowListStatus(state, adminAddr, precompile.AllowListAdmin) + rewardmanager.SetRewardManagerAllowListStatus(state, enabledAddr, precompile.AllowListEnabled) + rewardmanager.SetRewardManagerAllowListStatus(state, noRoleAddr, precompile.AllowListNoRole) if test.preCondition != nil { test.preCondition(t, state) @@ -1270,7 +1277,7 @@ func TestRewardManagerRun(t *testing.T) { if test.config != nil { test.config.Configure(params.TestChainConfig, state, blockContext) } - ret, remainingGas, err := precompile.RewardManagerPrecompile.Run(&mockAccessibleState{state: state, blockContext: blockContext, snowContext: snow.DefaultContextTest()}, test.caller, precompile.RewardManagerAddress, test.input(), test.suppliedGas, test.readOnly) + ret, remainingGas, err := rewardmanager.RewardManagerPrecompile.Run(&mockAccessibleState{state: state, blockContext: blockContext, snowContext: snow.DefaultContextTest()}, test.caller, precompile.RewardManagerAddress, test.input(), test.suppliedGas, test.readOnly) if len(test.expectedErr) != 0 { require.ErrorContains(t, err, test.expectedErr) } else { diff --git a/core/test_blockchain.go b/core/test_blockchain.go index 29b465a22f..c1254ee005 100644 --- a/core/test_blockchain.go +++ b/core/test_blockchain.go @@ -17,6 +17,8 @@ import ( "github.com/ava-labs/subnet-evm/ethdb" "github.com/ava-labs/subnet-evm/params" "github.com/ava-labs/subnet-evm/precompile" + "github.com/ava-labs/subnet-evm/precompile/deployerallowlist" + "github.com/ava-labs/subnet-evm/precompile/feemanager" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" "github.com/stretchr/testify/assert" @@ -1546,8 +1548,8 @@ func TestStatefulPrecompiles(t *testing.T, create func(db ethdb.Database, chainC genesisBalance := new(big.Int).Mul(big.NewInt(1000000), big.NewInt(params.Ether)) config := *params.TestChainConfig // Set all of the required config parameters - config.ContractDeployerAllowListConfig = precompile.NewContractDeployerAllowListConfig(big.NewInt(0), []common.Address{addr1}, nil) - config.FeeManagerConfig = precompile.NewFeeManagerConfig(big.NewInt(0), []common.Address{addr1}, nil, nil) + config.ContractDeployerAllowListConfig = deployerallowlist.NewContractDeployerAllowListConfig(big.NewInt(0), []common.Address{addr1}, nil) + config.FeeManagerConfig = feemanager.NewFeeManagerConfig(big.NewInt(0), []common.Address{addr1}, nil, nil) gspec := &Genesis{ Config: &config, Alloc: GenesisAlloc{addr1: {Balance: genesisBalance}}, @@ -1609,22 +1611,22 @@ func TestStatefulPrecompiles(t *testing.T, create func(db ethdb.Database, chainC gen.AddTx(signedTx) }, verifyState: func(sdb *state.StateDB) error { - res := precompile.GetContractDeployerAllowListStatus(sdb, addr1) + res := deployerallowlist.GetContractDeployerAllowListStatus(sdb, addr1) if precompile.AllowListAdmin != res { return fmt.Errorf("unexpected allow list status for addr1 %s, expected %s", res, precompile.AllowListAdmin) } - res = precompile.GetContractDeployerAllowListStatus(sdb, addr2) + res = deployerallowlist.GetContractDeployerAllowListStatus(sdb, addr2) if precompile.AllowListAdmin != res { return fmt.Errorf("unexpected allow list status for addr2 %s, expected %s", res, precompile.AllowListAdmin) } return nil }, verifyGenesis: func(sdb *state.StateDB) { - res := precompile.GetContractDeployerAllowListStatus(sdb, addr1) + res := deployerallowlist.GetContractDeployerAllowListStatus(sdb, addr1) if precompile.AllowListAdmin != res { t.Fatalf("unexpected allow list status for addr1 %s, expected %s", res, precompile.AllowListAdmin) } - res = precompile.GetContractDeployerAllowListStatus(sdb, addr2) + res = deployerallowlist.GetContractDeployerAllowListStatus(sdb, addr2) if precompile.AllowListNoRole != res { t.Fatalf("unexpected allow list status for addr2 %s, expected %s", res, precompile.AllowListNoRole) } @@ -1633,7 +1635,7 @@ func TestStatefulPrecompiles(t *testing.T, create func(db ethdb.Database, chainC "fee manager set config": { addTx: func(gen *BlockGen) { feeCap := new(big.Int).Add(gen.BaseFee(), tip) - input, err := precompile.PackSetFeeConfig(testFeeConfig) + input, err := feemanager.PackSetFeeConfig(testFeeConfig) if err != nil { t.Fatal(err) } @@ -1655,10 +1657,10 @@ func TestStatefulPrecompiles(t *testing.T, create func(db ethdb.Database, chainC gen.AddTx(signedTx) }, verifyState: func(sdb *state.StateDB) error { - res := precompile.GetFeeConfigManagerStatus(sdb, addr1) + res := feemanager.GetFeeConfigManagerStatus(sdb, addr1) assert.Equal(precompile.AllowListAdmin, res) - storedConfig := precompile.GetStoredFeeConfig(sdb) + storedConfig := feemanager.GetStoredFeeConfig(sdb) assert.EqualValues(testFeeConfig, storedConfig) feeConfig, _, err := blockchain.GetFeeConfigAt(blockchain.CurrentHeader()) @@ -1667,7 +1669,7 @@ func TestStatefulPrecompiles(t *testing.T, create func(db ethdb.Database, chainC return nil }, verifyGenesis: func(sdb *state.StateDB) { - res := precompile.GetFeeConfigManagerStatus(sdb, addr1) + res := feemanager.GetFeeConfigManagerStatus(sdb, addr1) assert.Equal(precompile.AllowListAdmin, res) feeConfig, _, err := blockchain.GetFeeConfigAt(blockchain.Genesis().Header()) diff --git a/core/tx_pool.go b/core/tx_pool.go index f927cb9589..f7d64ad828 100644 --- a/core/tx_pool.go +++ b/core/tx_pool.go @@ -43,6 +43,7 @@ import ( "github.com/ava-labs/subnet-evm/metrics" "github.com/ava-labs/subnet-evm/params" "github.com/ava-labs/subnet-evm/precompile" + "github.com/ava-labs/subnet-evm/precompile/txallowlist" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/prque" "github.com/ethereum/go-ethereum/event" @@ -694,9 +695,9 @@ func (pool *TxPool) checkTxState(from common.Address, tx *types.Transaction) err // If the tx allow list is enabled, return an error if the from address is not allow listed. headTimestamp := big.NewInt(int64(pool.currentHead.Time)) if pool.chainconfig.IsPrecompileEnabled(precompile.TxAllowListAddress, headTimestamp) { - txAllowListRole := precompile.GetTxAllowListStatus(pool.currentState, from) + txAllowListRole := txallowlist.GetTxAllowListStatus(pool.currentState, from) if !txAllowListRole.IsEnabled() { - return fmt.Errorf("%w: %s", precompile.ErrSenderAddressNotAllowListed, from) + return fmt.Errorf("%w: %s", txallowlist.ErrSenderAddressNotAllowListed, from) } } return nil diff --git a/core/vm/evm.go b/core/vm/evm.go index bb4b14b3e8..86849d05ad 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -36,6 +36,7 @@ import ( "github.com/ava-labs/subnet-evm/constants" "github.com/ava-labs/subnet-evm/params" "github.com/ava-labs/subnet-evm/precompile" + "github.com/ava-labs/subnet-evm/precompile/deployerallowlist" "github.com/ava-labs/subnet-evm/vmerrs" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" @@ -508,7 +509,7 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64, } // If the allow list is enabled, check that [evm.TxContext.Origin] has permission to deploy a contract. if evm.chainRules.IsPrecompileEnabled(precompile.ContractDeployerAllowListAddress) { - allowListRole := precompile.GetContractDeployerAllowListStatus(evm.StateDB, evm.TxContext.Origin) + allowListRole := deployerallowlist.GetContractDeployerAllowListStatus(evm.StateDB, evm.TxContext.Origin) if !allowListRole.IsEnabled() { return nil, common.Address{}, 0, fmt.Errorf("tx.origin %s is not authorized to deploy a contract", evm.TxContext.Origin) } diff --git a/eth/gasprice/gasprice_test.go b/eth/gasprice/gasprice_test.go index 62e770564f..0ed41c7df9 100644 --- a/eth/gasprice/gasprice_test.go +++ b/eth/gasprice/gasprice_test.go @@ -41,6 +41,7 @@ import ( "github.com/ava-labs/subnet-evm/ethdb" "github.com/ava-labs/subnet-evm/params" "github.com/ava-labs/subnet-evm/precompile" + "github.com/ava-labs/subnet-evm/precompile/feemanager" "github.com/ava-labs/subnet-evm/rpc" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" @@ -434,13 +435,13 @@ func TestSuggestGasPriceAfterFeeConfigUpdate(t *testing.T) { // create a chain config with fee manager enabled at genesis with [addr] as the admin chainConfig := *params.TestChainConfig - chainConfig.FeeManagerConfig = precompile.NewFeeManagerConfig(big.NewInt(0), []common.Address{addr}, nil, nil) + chainConfig.FeeManagerConfig = feemanager.NewFeeManagerConfig(big.NewInt(0), []common.Address{addr}, nil, nil) // create a fee config with higher MinBaseFee and prepare it for inclusion in a tx signer := types.LatestSigner(params.TestChainConfig) highFeeConfig := chainConfig.FeeConfig highFeeConfig.MinBaseFee = big.NewInt(28_000_000_000) - data, err := precompile.PackSetFeeConfig(highFeeConfig) + data, err := feemanager.PackSetFeeConfig(highFeeConfig) require.NoError(err) // before issuing the block changing the fee into the chain, the fee estimation should diff --git a/params/precompile_config.go b/params/precompile_config.go index cd629ced55..e19c3041f7 100644 --- a/params/precompile_config.go +++ b/params/precompile_config.go @@ -8,6 +8,11 @@ import ( "math/big" "github.com/ava-labs/subnet-evm/precompile" + "github.com/ava-labs/subnet-evm/precompile/deployerallowlist" + "github.com/ava-labs/subnet-evm/precompile/feemanager" + "github.com/ava-labs/subnet-evm/precompile/nativeminter" + "github.com/ava-labs/subnet-evm/precompile/rewardmanager" + "github.com/ava-labs/subnet-evm/precompile/txallowlist" "github.com/ava-labs/subnet-evm/utils" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/log" @@ -17,11 +22,11 @@ import ( // each of the possible stateful precompile types that can be activated // as a network upgrade. type PrecompileUpgrade struct { - ContractDeployerAllowListConfig *precompile.ContractDeployerAllowListConfig `json:"contractDeployerAllowListConfig,omitempty"` // Config for the contract deployer allow list precompile - ContractNativeMinterConfig *precompile.ContractNativeMinterConfig `json:"contractNativeMinterConfig,omitempty"` // Config for the native minter precompile - TxAllowListConfig *precompile.TxAllowListConfig `json:"txAllowListConfig,omitempty"` // Config for the tx allow list precompile - FeeManagerConfig *precompile.FeeConfigManagerConfig `json:"feeManagerConfig,omitempty"` // Config for the fee manager precompile - RewardManagerConfig *precompile.RewardManagerConfig `json:"rewardManagerConfig,omitempty"` // Config for the reward manager precompile + ContractDeployerAllowListConfig *deployerallowlist.ContractDeployerAllowListConfig `json:"contractDeployerAllowListConfig,omitempty"` // Config for the contract deployer allow list precompile + ContractNativeMinterConfig *nativeminter.ContractNativeMinterConfig `json:"contractNativeMinterConfig,omitempty"` // Config for the native minter precompile + TxAllowListConfig *txallowlist.TxAllowListConfig `json:"txAllowListConfig,omitempty"` // Config for the tx allow list precompile + FeeManagerConfig *feemanager.FeeConfigManagerConfig `json:"feeManagerConfig,omitempty"` // Config for the fee manager precompile + RewardManagerConfig *rewardmanager.RewardManagerConfig `json:"rewardManagerConfig,omitempty"` // Config for the reward manager precompile // ADD YOUR PRECOMPILE HERE // {YourPrecompile}Config *precompile.{YourPrecompile}Config `json:"{yourPrecompile}Config,omitempty"` } @@ -171,19 +176,19 @@ func (c *ChainConfig) GetPrecompileConfig(address common.Address, blockTimestamp func (c *ChainConfig) GetActivePrecompileUpgrade(blockTimestamp *big.Int) PrecompileUpgrade { pu := PrecompileUpgrade{} if config := c.GetPrecompileConfig(precompile.ContractDeployerAllowListAddress, blockTimestamp); config != nil && !config.IsDisabled() { - pu.ContractDeployerAllowListConfig = config.(*precompile.ContractDeployerAllowListConfig) + pu.ContractDeployerAllowListConfig = config.(*deployerallowlist.ContractDeployerAllowListConfig) } if config := c.GetPrecompileConfig(precompile.ContractNativeMinterAddress, blockTimestamp); config != nil && !config.IsDisabled() { - pu.ContractNativeMinterConfig = config.(*precompile.ContractNativeMinterConfig) + pu.ContractNativeMinterConfig = config.(*nativeminter.ContractNativeMinterConfig) } if config := c.GetPrecompileConfig(precompile.TxAllowListAddress, blockTimestamp); config != nil && !config.IsDisabled() { - pu.TxAllowListConfig = config.(*precompile.TxAllowListConfig) + pu.TxAllowListConfig = config.(*txallowlist.TxAllowListConfig) } if config := c.GetPrecompileConfig(precompile.FeeConfigManagerAddress, blockTimestamp); config != nil && !config.IsDisabled() { - pu.FeeManagerConfig = config.(*precompile.FeeConfigManagerConfig) + pu.FeeManagerConfig = config.(*feemanager.FeeConfigManagerConfig) } if config := c.GetPrecompileConfig(precompile.RewardManagerAddress, blockTimestamp); config != nil && !config.IsDisabled() { - pu.RewardManagerConfig = config.(*precompile.RewardManagerConfig) + pu.RewardManagerConfig = config.(*rewardmanager.RewardManagerConfig) } // ADD YOUR PRECOMPILE HERE diff --git a/params/precompile_config_test.go b/params/precompile_config_test.go index 3ac584aec4..4d7a114d14 100644 --- a/params/precompile_config_test.go +++ b/params/precompile_config_test.go @@ -9,6 +9,9 @@ import ( "github.com/ava-labs/subnet-evm/commontype" "github.com/ava-labs/subnet-evm/precompile" + "github.com/ava-labs/subnet-evm/precompile/deployerallowlist" + "github.com/ava-labs/subnet-evm/precompile/feemanager" + "github.com/ava-labs/subnet-evm/precompile/txallowlist" "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -19,16 +22,16 @@ func TestVerifyWithChainConfig(t *testing.T) { baseConfig := *SubnetEVMDefaultChainConfig config := &baseConfig config.PrecompileUpgrade = PrecompileUpgrade{ - TxAllowListConfig: precompile.NewTxAllowListConfig(big.NewInt(2), nil, nil), + TxAllowListConfig: txallowlist.NewTxAllowListConfig(big.NewInt(2), nil, nil), } config.PrecompileUpgrades = []PrecompileUpgrade{ { // disable TxAllowList at timestamp 4 - TxAllowListConfig: precompile.NewDisableTxAllowListConfig(big.NewInt(4)), + TxAllowListConfig: txallowlist.NewDisableTxAllowListConfig(big.NewInt(4)), }, { // re-enable TxAllowList at timestamp 5 - TxAllowListConfig: precompile.NewTxAllowListConfig(big.NewInt(5), admins, nil), + TxAllowListConfig: txallowlist.NewTxAllowListConfig(big.NewInt(5), admins, nil), }, } @@ -41,7 +44,7 @@ func TestVerifyWithChainConfig(t *testing.T) { badConfig.PrecompileUpgrades = append( badConfig.PrecompileUpgrades, PrecompileUpgrade{ - TxAllowListConfig: precompile.NewDisableTxAllowListConfig(big.NewInt(5)), + TxAllowListConfig: txallowlist.NewDisableTxAllowListConfig(big.NewInt(5)), }, ) err = badConfig.Verify() @@ -52,7 +55,7 @@ func TestVerifyWithChainConfig(t *testing.T) { badConfig.PrecompileUpgrades = append( badConfig.PrecompileUpgrades, PrecompileUpgrade{ - TxAllowListConfig: precompile.NewTxAllowListConfig(big.NewInt(5), admins, nil), + TxAllowListConfig: txallowlist.NewTxAllowListConfig(big.NewInt(5), admins, nil), }, ) err = badConfig.Verify() @@ -70,10 +73,10 @@ func TestVerifyPrecompileUpgrades(t *testing.T) { name: "enable and disable tx allow list", upgrades: []PrecompileUpgrade{ { - TxAllowListConfig: precompile.NewTxAllowListConfig(big.NewInt(1), admins, nil), + TxAllowListConfig: txallowlist.NewTxAllowListConfig(big.NewInt(1), admins, nil), }, { - TxAllowListConfig: precompile.NewDisableTxAllowListConfig(big.NewInt(2)), + TxAllowListConfig: txallowlist.NewDisableTxAllowListConfig(big.NewInt(2)), }, }, expectedError: "", @@ -82,13 +85,13 @@ func TestVerifyPrecompileUpgrades(t *testing.T) { name: "invalid allow list config in tx allowlist", upgrades: []PrecompileUpgrade{ { - TxAllowListConfig: precompile.NewTxAllowListConfig(big.NewInt(1), admins, nil), + TxAllowListConfig: txallowlist.NewTxAllowListConfig(big.NewInt(1), admins, nil), }, { - TxAllowListConfig: precompile.NewDisableTxAllowListConfig(big.NewInt(2)), + TxAllowListConfig: txallowlist.NewDisableTxAllowListConfig(big.NewInt(2)), }, { - TxAllowListConfig: precompile.NewTxAllowListConfig(big.NewInt(3), admins, admins), + TxAllowListConfig: txallowlist.NewTxAllowListConfig(big.NewInt(3), admins, admins), }, }, expectedError: "cannot set address", @@ -97,7 +100,7 @@ func TestVerifyPrecompileUpgrades(t *testing.T) { name: "invalid initial fee manager config", upgrades: []PrecompileUpgrade{ { - FeeManagerConfig: precompile.NewFeeManagerConfig(big.NewInt(3), admins, nil, + FeeManagerConfig: feemanager.NewFeeManagerConfig(big.NewInt(3), admins, nil, &commontype.FeeConfig{ GasLimit: big.NewInt(-1), }), @@ -109,7 +112,7 @@ func TestVerifyPrecompileUpgrades(t *testing.T) { name: "invalid initial fee manager config gas limit 0", upgrades: []PrecompileUpgrade{ { - FeeManagerConfig: precompile.NewFeeManagerConfig(big.NewInt(3), admins, nil, + FeeManagerConfig: feemanager.NewFeeManagerConfig(big.NewInt(3), admins, nil, &commontype.FeeConfig{ GasLimit: big.NewInt(0), }), @@ -145,14 +148,14 @@ func TestVerifyPrecompiles(t *testing.T) { { name: "invalid allow list config in tx allowlist", upgrade: PrecompileUpgrade{ - TxAllowListConfig: precompile.NewTxAllowListConfig(big.NewInt(3), admins, admins), + TxAllowListConfig: txallowlist.NewTxAllowListConfig(big.NewInt(3), admins, admins), }, expectedError: "cannot set address", }, { name: "invalid initial fee manager config", upgrade: PrecompileUpgrade{ - FeeManagerConfig: precompile.NewFeeManagerConfig(big.NewInt(3), admins, nil, + FeeManagerConfig: feemanager.NewFeeManagerConfig(big.NewInt(3), admins, nil, &commontype.FeeConfig{ GasLimit: big.NewInt(-1), }), @@ -183,10 +186,10 @@ func TestVerifyRequiresSortedTimestamps(t *testing.T) { config := &baseConfig config.PrecompileUpgrades = []PrecompileUpgrade{ { - TxAllowListConfig: precompile.NewTxAllowListConfig(big.NewInt(2), admins, nil), + TxAllowListConfig: txallowlist.NewTxAllowListConfig(big.NewInt(2), admins, nil), }, { - ContractDeployerAllowListConfig: precompile.NewContractDeployerAllowListConfig(big.NewInt(1), admins, nil), + ContractDeployerAllowListConfig: deployerallowlist.NewContractDeployerAllowListConfig(big.NewInt(1), admins, nil), }, } @@ -200,7 +203,7 @@ func TestGetPrecompileConfig(t *testing.T) { baseConfig := *SubnetEVMDefaultChainConfig config := &baseConfig config.PrecompileUpgrade = PrecompileUpgrade{ - ContractDeployerAllowListConfig: precompile.NewContractDeployerAllowListConfig(big.NewInt(10), nil, nil), + ContractDeployerAllowListConfig: deployerallowlist.NewContractDeployerAllowListConfig(big.NewInt(10), nil, nil), } deployerConfig := config.GetPrecompileConfig(precompile.ContractDeployerAllowListAddress, big.NewInt(0)) diff --git a/params/upgrade_config_test.go b/params/upgrade_config_test.go index 38c93f5386..e8e5fb9750 100644 --- a/params/upgrade_config_test.go +++ b/params/upgrade_config_test.go @@ -7,7 +7,8 @@ import ( "math/big" "testing" - "github.com/ava-labs/subnet-evm/precompile" + "github.com/ava-labs/subnet-evm/precompile/deployerallowlist" + "github.com/ava-labs/subnet-evm/precompile/txallowlist" "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/assert" ) @@ -15,7 +16,7 @@ import ( func TestVerifyUpgradeConfig(t *testing.T) { admins := []common.Address{{1}} chainConfig := *TestChainConfig - chainConfig.TxAllowListConfig = precompile.NewTxAllowListConfig(big.NewInt(1), admins, nil) + chainConfig.TxAllowListConfig = txallowlist.NewTxAllowListConfig(big.NewInt(1), admins, nil) type test struct { upgrades []PrecompileUpgrade @@ -27,7 +28,7 @@ func TestVerifyUpgradeConfig(t *testing.T) { expectedErrorString: "disable should be [true]", upgrades: []PrecompileUpgrade{ { - TxAllowListConfig: precompile.NewTxAllowListConfig(big.NewInt(2), admins, nil), + TxAllowListConfig: txallowlist.NewTxAllowListConfig(big.NewInt(2), admins, nil), }, }, }, @@ -35,7 +36,7 @@ func TestVerifyUpgradeConfig(t *testing.T) { expectedErrorString: "config timestamp (0) <= previous timestamp (1)", upgrades: []PrecompileUpgrade{ { - TxAllowListConfig: precompile.NewDisableTxAllowListConfig(big.NewInt(0)), + TxAllowListConfig: txallowlist.NewDisableTxAllowListConfig(big.NewInt(0)), }, }, }, @@ -43,7 +44,7 @@ func TestVerifyUpgradeConfig(t *testing.T) { expectedErrorString: "config timestamp (1) <= previous timestamp (1)", upgrades: []PrecompileUpgrade{ { - TxAllowListConfig: precompile.NewDisableTxAllowListConfig(big.NewInt(1)), + TxAllowListConfig: txallowlist.NewDisableTxAllowListConfig(big.NewInt(1)), }, }, }, @@ -70,8 +71,8 @@ func TestVerifyUpgradeConfig(t *testing.T) { func TestCheckCompatibleUpgradeConfigs(t *testing.T) { admins := []common.Address{{1}} chainConfig := *TestChainConfig - chainConfig.TxAllowListConfig = precompile.NewTxAllowListConfig(big.NewInt(1), admins, nil) - chainConfig.ContractDeployerAllowListConfig = precompile.NewContractDeployerAllowListConfig(big.NewInt(10), admins, nil) + chainConfig.TxAllowListConfig = txallowlist.NewTxAllowListConfig(big.NewInt(1), admins, nil) + chainConfig.ContractDeployerAllowListConfig = deployerallowlist.NewContractDeployerAllowListConfig(big.NewInt(10), admins, nil) type test struct { configs []*UpgradeConfig @@ -86,10 +87,10 @@ func TestCheckCompatibleUpgradeConfigs(t *testing.T) { { PrecompileUpgrades: []PrecompileUpgrade{ { - TxAllowListConfig: precompile.NewDisableTxAllowListConfig(big.NewInt(6)), + TxAllowListConfig: txallowlist.NewDisableTxAllowListConfig(big.NewInt(6)), }, { - TxAllowListConfig: precompile.NewTxAllowListConfig(big.NewInt(7), admins, nil), + TxAllowListConfig: txallowlist.NewTxAllowListConfig(big.NewInt(7), admins, nil), }, }, }, @@ -101,20 +102,20 @@ func TestCheckCompatibleUpgradeConfigs(t *testing.T) { { PrecompileUpgrades: []PrecompileUpgrade{ { - TxAllowListConfig: precompile.NewDisableTxAllowListConfig(big.NewInt(6)), + TxAllowListConfig: txallowlist.NewDisableTxAllowListConfig(big.NewInt(6)), }, { - TxAllowListConfig: precompile.NewTxAllowListConfig(big.NewInt(7), admins, nil), + TxAllowListConfig: txallowlist.NewTxAllowListConfig(big.NewInt(7), admins, nil), }, }, }, { PrecompileUpgrades: []PrecompileUpgrade{ { - TxAllowListConfig: precompile.NewDisableTxAllowListConfig(big.NewInt(6)), + TxAllowListConfig: txallowlist.NewDisableTxAllowListConfig(big.NewInt(6)), }, { - TxAllowListConfig: precompile.NewTxAllowListConfig(big.NewInt(8), admins, nil), + TxAllowListConfig: txallowlist.NewTxAllowListConfig(big.NewInt(8), admins, nil), }, }, }, @@ -127,20 +128,20 @@ func TestCheckCompatibleUpgradeConfigs(t *testing.T) { { PrecompileUpgrades: []PrecompileUpgrade{ { - TxAllowListConfig: precompile.NewDisableTxAllowListConfig(big.NewInt(6)), + TxAllowListConfig: txallowlist.NewDisableTxAllowListConfig(big.NewInt(6)), }, { - TxAllowListConfig: precompile.NewTxAllowListConfig(big.NewInt(7), admins, nil), + TxAllowListConfig: txallowlist.NewTxAllowListConfig(big.NewInt(7), admins, nil), }, }, }, { PrecompileUpgrades: []PrecompileUpgrade{ { - TxAllowListConfig: precompile.NewDisableTxAllowListConfig(big.NewInt(6)), + TxAllowListConfig: txallowlist.NewDisableTxAllowListConfig(big.NewInt(6)), }, { - TxAllowListConfig: precompile.NewTxAllowListConfig(big.NewInt(8), admins, nil), + TxAllowListConfig: txallowlist.NewTxAllowListConfig(big.NewInt(8), admins, nil), }, }, }, @@ -152,17 +153,17 @@ func TestCheckCompatibleUpgradeConfigs(t *testing.T) { { PrecompileUpgrades: []PrecompileUpgrade{ { - TxAllowListConfig: precompile.NewDisableTxAllowListConfig(big.NewInt(6)), + TxAllowListConfig: txallowlist.NewDisableTxAllowListConfig(big.NewInt(6)), }, { - TxAllowListConfig: precompile.NewTxAllowListConfig(big.NewInt(7), admins, nil), + TxAllowListConfig: txallowlist.NewTxAllowListConfig(big.NewInt(7), admins, nil), }, }, }, { PrecompileUpgrades: []PrecompileUpgrade{ { - TxAllowListConfig: precompile.NewDisableTxAllowListConfig(big.NewInt(6)), + TxAllowListConfig: txallowlist.NewDisableTxAllowListConfig(big.NewInt(6)), }, }, }, @@ -175,17 +176,17 @@ func TestCheckCompatibleUpgradeConfigs(t *testing.T) { { PrecompileUpgrades: []PrecompileUpgrade{ { - TxAllowListConfig: precompile.NewDisableTxAllowListConfig(big.NewInt(6)), + TxAllowListConfig: txallowlist.NewDisableTxAllowListConfig(big.NewInt(6)), }, { - TxAllowListConfig: precompile.NewTxAllowListConfig(big.NewInt(7), admins, nil), + TxAllowListConfig: txallowlist.NewTxAllowListConfig(big.NewInt(7), admins, nil), }, }, }, { PrecompileUpgrades: []PrecompileUpgrade{ { - TxAllowListConfig: precompile.NewDisableTxAllowListConfig(big.NewInt(6)), + TxAllowListConfig: txallowlist.NewDisableTxAllowListConfig(big.NewInt(6)), }, }, }, @@ -198,21 +199,21 @@ func TestCheckCompatibleUpgradeConfigs(t *testing.T) { { PrecompileUpgrades: []PrecompileUpgrade{ { - TxAllowListConfig: precompile.NewDisableTxAllowListConfig(big.NewInt(6)), + TxAllowListConfig: txallowlist.NewDisableTxAllowListConfig(big.NewInt(6)), }, { - TxAllowListConfig: precompile.NewTxAllowListConfig(big.NewInt(7), admins, nil), + TxAllowListConfig: txallowlist.NewTxAllowListConfig(big.NewInt(7), admins, nil), }, }, }, { PrecompileUpgrades: []PrecompileUpgrade{ { - TxAllowListConfig: precompile.NewDisableTxAllowListConfig(big.NewInt(6)), + TxAllowListConfig: txallowlist.NewDisableTxAllowListConfig(big.NewInt(6)), }, { // uses a different (empty) admin list, not allowed - TxAllowListConfig: precompile.NewTxAllowListConfig(big.NewInt(7), []common.Address{}, nil), + TxAllowListConfig: txallowlist.NewTxAllowListConfig(big.NewInt(7), []common.Address{}, nil), }, }, }, @@ -224,20 +225,20 @@ func TestCheckCompatibleUpgradeConfigs(t *testing.T) { { PrecompileUpgrades: []PrecompileUpgrade{ { - TxAllowListConfig: precompile.NewDisableTxAllowListConfig(big.NewInt(6)), + TxAllowListConfig: txallowlist.NewDisableTxAllowListConfig(big.NewInt(6)), }, { - TxAllowListConfig: precompile.NewTxAllowListConfig(big.NewInt(7), admins, nil), + TxAllowListConfig: txallowlist.NewTxAllowListConfig(big.NewInt(7), admins, nil), }, }, }, { PrecompileUpgrades: []PrecompileUpgrade{ { - TxAllowListConfig: precompile.NewDisableTxAllowListConfig(big.NewInt(6)), + TxAllowListConfig: txallowlist.NewDisableTxAllowListConfig(big.NewInt(6)), }, { - TxAllowListConfig: precompile.NewTxAllowListConfig(big.NewInt(7), admins, nil), + TxAllowListConfig: txallowlist.NewTxAllowListConfig(big.NewInt(7), admins, nil), }, }, }, diff --git a/plugin/evm/vm_test.go b/plugin/evm/vm_test.go index 839d0e7647..cbfbf92bdb 100644 --- a/plugin/evm/vm_test.go +++ b/plugin/evm/vm_test.go @@ -20,6 +20,10 @@ import ( "github.com/ava-labs/subnet-evm/commontype" "github.com/ava-labs/subnet-evm/metrics" "github.com/ava-labs/subnet-evm/precompile" + "github.com/ava-labs/subnet-evm/precompile/deployerallowlist" + "github.com/ava-labs/subnet-evm/precompile/feemanager" + "github.com/ava-labs/subnet-evm/precompile/rewardmanager" + "github.com/ava-labs/subnet-evm/precompile/txallowlist" "github.com/ava-labs/subnet-evm/trie" "github.com/ava-labs/subnet-evm/vmerrs" "github.com/ethereum/go-ethereum/common" @@ -2110,7 +2114,7 @@ func TestBuildAllowListActivationBlock(t *testing.T) { if err := genesis.UnmarshalJSON([]byte(genesisJSONSubnetEVM)); err != nil { t.Fatal(err) } - genesis.Config.ContractDeployerAllowListConfig = precompile.NewContractDeployerAllowListConfig(big.NewInt(time.Now().Unix()), testEthAddrs, nil) + genesis.Config.ContractDeployerAllowListConfig = deployerallowlist.NewContractDeployerAllowListConfig(big.NewInt(time.Now().Unix()), testEthAddrs, nil) genesisJSON, err := genesis.MarshalJSON() if err != nil { @@ -2131,7 +2135,7 @@ func TestBuildAllowListActivationBlock(t *testing.T) { if err != nil { t.Fatal(err) } - role := precompile.GetContractDeployerAllowListStatus(genesisState, testEthAddrs[0]) + role := deployerallowlist.GetContractDeployerAllowListStatus(genesisState, testEthAddrs[0]) if role != precompile.AllowListNoRole { t.Fatalf("Expected allow list status to be set to no role: %s, but found: %s", precompile.AllowListNoRole, role) } @@ -2161,7 +2165,7 @@ func TestBuildAllowListActivationBlock(t *testing.T) { if err != nil { t.Fatal(err) } - role = precompile.GetContractDeployerAllowListStatus(blkState, testEthAddrs[0]) + role = deployerallowlist.GetContractDeployerAllowListStatus(blkState, testEthAddrs[0]) if role != precompile.AllowListAdmin { t.Fatalf("Expected allow list status to be set to Admin: %s, but found: %s", precompile.AllowListAdmin, role) } @@ -2174,7 +2178,7 @@ func TestTxAllowListSuccessfulTx(t *testing.T) { if err := genesis.UnmarshalJSON([]byte(genesisJSONSubnetEVM)); err != nil { t.Fatal(err) } - genesis.Config.TxAllowListConfig = precompile.NewTxAllowListConfig(big.NewInt(0), testEthAddrs[0:1], nil) + genesis.Config.TxAllowListConfig = txallowlist.NewTxAllowListConfig(big.NewInt(0), testEthAddrs[0:1], nil) genesisJSON, err := genesis.MarshalJSON() if err != nil { t.Fatal(err) @@ -2196,11 +2200,11 @@ func TestTxAllowListSuccessfulTx(t *testing.T) { } // Check that address 0 is whitelisted and address 1 is not - role := precompile.GetTxAllowListStatus(genesisState, testEthAddrs[0]) + role := txallowlist.GetTxAllowListStatus(genesisState, testEthAddrs[0]) if role != precompile.AllowListAdmin { t.Fatalf("Expected allow list status to be set to admin: %s, but found: %s", precompile.AllowListAdmin, role) } - role = precompile.GetTxAllowListStatus(genesisState, testEthAddrs[1]) + role = txallowlist.GetTxAllowListStatus(genesisState, testEthAddrs[1]) if role != precompile.AllowListNoRole { t.Fatalf("Expected allow list status to be set to no role: %s, but found: %s", precompile.AllowListNoRole, role) } @@ -2223,7 +2227,7 @@ func TestTxAllowListSuccessfulTx(t *testing.T) { } errs = vm.txPool.AddRemotesSync([]*types.Transaction{signedTx1}) - if err := errs[0]; !errors.Is(err, precompile.ErrSenderAddressNotAllowListed) { + if err := errs[0]; !errors.Is(err, txallowlist.ErrSenderAddressNotAllowListed) { t.Fatalf("expected ErrSenderAddressNotAllowListed, got: %s", err) } @@ -2250,7 +2254,7 @@ func TestTxAllowListDisablePrecompile(t *testing.T) { t.Fatal(err) } enableAllowListTimestamp := time.Unix(0, 0) // enable at genesis - genesis.Config.TxAllowListConfig = precompile.NewTxAllowListConfig(big.NewInt(enableAllowListTimestamp.Unix()), testEthAddrs[0:1], nil) + genesis.Config.TxAllowListConfig = txallowlist.NewTxAllowListConfig(big.NewInt(enableAllowListTimestamp.Unix()), testEthAddrs[0:1], nil) genesisJSON, err := genesis.MarshalJSON() if err != nil { t.Fatal(err) @@ -2265,7 +2269,7 @@ func TestTxAllowListDisablePrecompile(t *testing.T) { precompileConfigs.PrecompileUpgrades = append( precompileConfigs.PrecompileUpgrades, params.PrecompileUpgrade{ - TxAllowListConfig: precompile.NewDisableTxAllowListConfig(big.NewInt(disableAllowListTimestamp.Unix())), + TxAllowListConfig: txallowlist.NewDisableTxAllowListConfig(big.NewInt(disableAllowListTimestamp.Unix())), }, ) @@ -2286,11 +2290,11 @@ func TestTxAllowListDisablePrecompile(t *testing.T) { } // Check that address 0 is whitelisted and address 1 is not - role := precompile.GetTxAllowListStatus(genesisState, testEthAddrs[0]) + role := txallowlist.GetTxAllowListStatus(genesisState, testEthAddrs[0]) if role != precompile.AllowListAdmin { t.Fatalf("Expected allow list status to be set to admin: %s, but found: %s", precompile.AllowListAdmin, role) } - role = precompile.GetTxAllowListStatus(genesisState, testEthAddrs[1]) + role = txallowlist.GetTxAllowListStatus(genesisState, testEthAddrs[1]) if role != precompile.AllowListNoRole { t.Fatalf("Expected allow list status to be set to no role: %s, but found: %s", precompile.AllowListNoRole, role) } @@ -2313,7 +2317,7 @@ func TestTxAllowListDisablePrecompile(t *testing.T) { } errs = vm.txPool.AddRemotesSync([]*types.Transaction{signedTx1}) - if err := errs[0]; !errors.Is(err, precompile.ErrSenderAddressNotAllowListed) { + if err := errs[0]; !errors.Is(err, txallowlist.ErrSenderAddressNotAllowListed) { t.Fatalf("expected ErrSenderAddressNotAllowListed, got: %s", err) } @@ -2357,7 +2361,7 @@ func TestFeeManagerChangeFee(t *testing.T) { if err := genesis.UnmarshalJSON([]byte(genesisJSONSubnetEVM)); err != nil { t.Fatal(err) } - genesis.Config.FeeManagerConfig = precompile.NewFeeManagerConfig(big.NewInt(0), testEthAddrs[0:1], nil, nil) + genesis.Config.FeeManagerConfig = feemanager.NewFeeManagerConfig(big.NewInt(0), testEthAddrs[0:1], nil, nil) // set a lower fee config now testLowFeeConfig := commontype.FeeConfig{ @@ -2395,11 +2399,11 @@ func TestFeeManagerChangeFee(t *testing.T) { } // Check that address 0 is whitelisted and address 1 is not - role := precompile.GetFeeConfigManagerStatus(genesisState, testEthAddrs[0]) + role := feemanager.GetFeeConfigManagerStatus(genesisState, testEthAddrs[0]) if role != precompile.AllowListAdmin { t.Fatalf("Expected fee manager list status to be set to admin: %s, but found: %s", precompile.FeeConfigManagerAddress, role) } - role = precompile.GetFeeConfigManagerStatus(genesisState, testEthAddrs[1]) + role = feemanager.GetFeeConfigManagerStatus(genesisState, testEthAddrs[1]) if role != precompile.AllowListNoRole { t.Fatalf("Expected fee manager list status to be set to no role: %s, but found: %s", precompile.FeeConfigManagerAddress, role) } @@ -2413,7 +2417,7 @@ func TestFeeManagerChangeFee(t *testing.T) { testHighFeeConfig := testLowFeeConfig testHighFeeConfig.MinBaseFee = big.NewInt(28_000_000_000) - data, err := precompile.PackSetFeeConfig(testHighFeeConfig) + data, err := feemanager.PackSetFeeConfig(testHighFeeConfig) assert.NoError(t, err) tx := types.NewTx(&types.DynamicFeeTx{ @@ -2597,7 +2601,7 @@ func TestRewardManagerPrecompileSetRewardAddress(t *testing.T) { genesis := &core.Genesis{} require.NoError(t, genesis.UnmarshalJSON([]byte(genesisJSONSubnetEVM))) - genesis.Config.RewardManagerConfig = precompile.NewRewardManagerConfig(common.Big0, testEthAddrs[0:1], nil, nil) + genesis.Config.RewardManagerConfig = rewardmanager.NewRewardManagerConfig(common.Big0, testEthAddrs[0:1], nil, nil) genesis.Config.AllowFeeRecipients = true // enable this in genesis to test if this is recognized by the reward manager genesisJSON, err := genesis.MarshalJSON() require.NoError(t, err) @@ -2620,10 +2624,10 @@ func TestRewardManagerPrecompileSetRewardAddress(t *testing.T) { vm.txPool.SubscribeNewReorgEvent(newTxPoolHeadChan) testAddr := common.HexToAddress("0x9999991111") - data, err := precompile.PackSetRewardAddress(testAddr) + data, err := rewardmanager.PackSetRewardAddress(testAddr) require.NoError(t, err) - gas := 21000 + 240 + precompile.SetRewardAddressGasCost // 21000 for tx, 240 for tx data + gas := 21000 + 240 + rewardmanager.SetRewardAddressGasCost // 21000 for tx, 240 for tx data tx := types.NewTransaction(uint64(0), precompile.RewardManagerAddress, big.NewInt(1), gas, big.NewInt(testMinGasPrice), data) @@ -2672,7 +2676,7 @@ func TestRewardManagerPrecompileSetRewardAddress(t *testing.T) { precompileConfigs.PrecompileUpgrades = append( precompileConfigs.PrecompileUpgrades, params.PrecompileUpgrade{ - RewardManagerConfig: precompile.NewDisableRewardManagerConfig(big.NewInt(disableTime.Unix())), + RewardManagerConfig: rewardmanager.NewDisableRewardManagerConfig(big.NewInt(disableTime.Unix())), }, ) @@ -2706,7 +2710,7 @@ func TestRewardManagerPrecompileAllowFeeRecipients(t *testing.T) { require.NoError(t, genesis.UnmarshalJSON([]byte(genesisJSONSubnetEVM))) enableRewardManagerTimestamp := time.Unix(0, 0) // enable at genesis - genesis.Config.RewardManagerConfig = precompile.NewRewardManagerConfig(big.NewInt(enableRewardManagerTimestamp.Unix()), testEthAddrs[0:1], nil, nil) + genesis.Config.RewardManagerConfig = rewardmanager.NewRewardManagerConfig(big.NewInt(enableRewardManagerTimestamp.Unix()), testEthAddrs[0:1], nil, nil) genesis.Config.AllowFeeRecipients = false // disable this in genesis genesisJSON, err := genesis.MarshalJSON() require.NoError(t, err) @@ -2725,10 +2729,10 @@ func TestRewardManagerPrecompileAllowFeeRecipients(t *testing.T) { newTxPoolHeadChan := make(chan core.NewTxPoolReorgEvent, 1) vm.txPool.SubscribeNewReorgEvent(newTxPoolHeadChan) - data, err := precompile.PackAllowFeeRecipients() + data, err := rewardmanager.PackAllowFeeRecipients() require.NoError(t, err) - gas := 21000 + 240 + precompile.AllowFeeRecipientsGasCost // 21000 for tx, 240 for tx data + gas := 21000 + 240 + rewardmanager.AllowFeeRecipientsGasCost // 21000 for tx, 240 for tx data tx := types.NewTransaction(uint64(0), precompile.RewardManagerAddress, big.NewInt(1), gas, big.NewInt(testMinGasPrice), data) @@ -2777,7 +2781,7 @@ func TestRewardManagerPrecompileAllowFeeRecipients(t *testing.T) { precompileConfigs.PrecompileUpgrades = append( precompileConfigs.PrecompileUpgrades, params.PrecompileUpgrade{ - RewardManagerConfig: precompile.NewDisableRewardManagerConfig(big.NewInt(disableTime.Unix())), + RewardManagerConfig: rewardmanager.NewDisableRewardManagerConfig(big.NewInt(disableTime.Unix())), }, ) diff --git a/plugin/evm/vm_upgrade_bytes_test.go b/plugin/evm/vm_upgrade_bytes_test.go index 22c78b5800..2adca151fe 100644 --- a/plugin/evm/vm_upgrade_bytes_test.go +++ b/plugin/evm/vm_upgrade_bytes_test.go @@ -18,7 +18,7 @@ import ( "github.com/ava-labs/subnet-evm/core/types" "github.com/ava-labs/subnet-evm/metrics" "github.com/ava-labs/subnet-evm/params" - "github.com/ava-labs/subnet-evm/precompile" + "github.com/ava-labs/subnet-evm/precompile/txallowlist" "github.com/stretchr/testify/assert" ) @@ -28,7 +28,7 @@ func TestVMUpgradeBytesPrecompile(t *testing.T) { upgradeConfig := ¶ms.UpgradeConfig{ PrecompileUpgrades: []params.PrecompileUpgrade{ { - TxAllowListConfig: precompile.NewTxAllowListConfig(big.NewInt(enableAllowListTimestamp.Unix()), testEthAddrs[0:1], nil), + TxAllowListConfig: txallowlist.NewTxAllowListConfig(big.NewInt(enableAllowListTimestamp.Unix()), testEthAddrs[0:1], nil), }, }, } @@ -57,7 +57,7 @@ func TestVMUpgradeBytesPrecompile(t *testing.T) { t.Fatal(err) } errs = vm.txPool.AddRemotesSync([]*types.Transaction{signedTx1}) - if err := errs[0]; !errors.Is(err, precompile.ErrSenderAddressNotAllowListed) { + if err := errs[0]; !errors.Is(err, txallowlist.ErrSenderAddressNotAllowListed) { t.Fatalf("expected ErrSenderAddressNotAllowListed, got: %s", err) } @@ -71,7 +71,7 @@ func TestVMUpgradeBytesPrecompile(t *testing.T) { upgradeConfig.PrecompileUpgrades = append( upgradeConfig.PrecompileUpgrades, params.PrecompileUpgrade{ - TxAllowListConfig: precompile.NewDisableTxAllowListConfig(big.NewInt(disableAllowListTimestamp.Unix())), + TxAllowListConfig: txallowlist.NewDisableTxAllowListConfig(big.NewInt(disableAllowListTimestamp.Unix())), }, ) upgradeBytesJSON, err = json.Marshal(upgradeConfig) @@ -108,7 +108,7 @@ func TestVMUpgradeBytesPrecompile(t *testing.T) { // Submit a rejected transaction, should throw an error errs = vm.txPool.AddRemotesSync([]*types.Transaction{signedTx1}) - if err := errs[0]; !errors.Is(err, precompile.ErrSenderAddressNotAllowListed) { + if err := errs[0]; !errors.Is(err, txallowlist.ErrSenderAddressNotAllowListed) { t.Fatalf("expected ErrSenderAddressNotAllowListed, got: %s", err) } diff --git a/precompile/allow_list.go b/precompile/allow_list.go index a22b9f110c..9e1f867a51 100644 --- a/precompile/allow_list.go +++ b/precompile/allow_list.go @@ -139,7 +139,7 @@ func SetAllowListRole(stateDB StateDB, precompileAddr, address common.Address, r // selector that should be encoded in the input. func PackModifyAllowList(address common.Address, role AllowListRole) ([]byte, error) { // function selector (4 bytes) + hash for address - input := make([]byte, 0, selectorLen+common.HashLength) + input := make([]byte, 0, SelectorLen+common.HashLength) switch role { case AllowListAdmin: @@ -158,7 +158,7 @@ func PackModifyAllowList(address common.Address, role AllowListRole) ([]byte, er // PackReadAllowList packs [address] into the input data to the read allow list function func PackReadAllowList(address common.Address) []byte { - input := make([]byte, 0, selectorLen+common.HashLength) + input := make([]byte, 0, SelectorLen+common.HashLength) input = append(input, readAllowListSignature...) input = append(input, address.Hash().Bytes()...) return input @@ -217,7 +217,7 @@ func createReadAllowList(precompileAddr common.Address) RunStatefulPrecompileFun } // createAllowListPrecompile returns a StatefulPrecompiledContract with R/W control of an allow list at [precompileAddr] -func createAllowListPrecompile(precompileAddr common.Address) StatefulPrecompiledContract { +func CreateAllowListPrecompile(precompileAddr common.Address) StatefulPrecompiledContract { // Construct the contract with no fallback function. allowListFuncs := CreateAllowListFunctions(precompileAddr) contract, err := NewStatefulPrecompileContract(nil, allowListFuncs) diff --git a/precompile/config_test.go b/precompile/config_test.go deleted file mode 100644 index 67ed5dbf85..0000000000 --- a/precompile/config_test.go +++ /dev/null @@ -1,390 +0,0 @@ -// (c) 2022 Ava Labs, Inc. All rights reserved. -// See the file LICENSE for licensing terms. - -package precompile - -import ( - "math/big" - "testing" - - "github.com/ava-labs/subnet-evm/commontype" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/math" - "github.com/stretchr/testify/require" -) - -var validFeeConfig = 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), -} - -func TestVerifyPrecompileUpgrades(t *testing.T) { - admins := []common.Address{{1}} - enableds := []common.Address{{2}} - tests := []struct { - name string - config StatefulPrecompileConfig - expectedError string - }{ - { - name: "invalid allow list config in tx allowlist", - config: NewTxAllowListConfig(big.NewInt(3), admins, admins), - expectedError: "cannot set address", - }, - { - name: "nil member allow list config in tx allowlist", - config: NewTxAllowListConfig(big.NewInt(3), nil, nil), - expectedError: "", - }, - { - name: "empty member allow list config in tx allowlist", - config: NewTxAllowListConfig(big.NewInt(3), []common.Address{}, []common.Address{}), - expectedError: "", - }, - { - name: "valid allow list config in tx allowlist", - config: NewTxAllowListConfig(big.NewInt(3), admins, enableds), - expectedError: "", - }, - { - name: "invalid allow list config in deployer allowlist", - config: NewContractDeployerAllowListConfig(big.NewInt(3), admins, admins), - expectedError: "cannot set address", - }, - { - name: "invalid allow list config in native minter allowlist", - config: NewContractNativeMinterConfig(big.NewInt(3), admins, admins, nil), - expectedError: "cannot set address", - }, - { - name: "duplicate admins in config in native minter allowlist", - config: NewContractNativeMinterConfig(big.NewInt(3), append(admins, admins[0]), enableds, nil), - expectedError: "duplicate address", - }, - { - name: "duplicate enableds in config in native minter allowlist", - config: NewContractNativeMinterConfig(big.NewInt(3), admins, append(enableds, enableds[0]), nil), - expectedError: "duplicate address", - }, - { - name: "invalid allow list config in fee manager allowlist", - config: NewFeeManagerConfig(big.NewInt(3), admins, admins, nil), - expectedError: "cannot set address", - }, - { - name: "invalid initial fee manager config", - config: NewFeeManagerConfig(big.NewInt(3), admins, nil, - &commontype.FeeConfig{ - GasLimit: big.NewInt(0), - }), - expectedError: "gasLimit = 0 cannot be less than or equal to 0", - }, - { - name: "nil amount in native minter config", - config: NewContractNativeMinterConfig(big.NewInt(3), admins, nil, - map[common.Address]*math.HexOrDecimal256{ - common.HexToAddress("0x01"): math.NewHexOrDecimal256(123), - common.HexToAddress("0x02"): nil, - }), - expectedError: "initial mint cannot contain nil", - }, - { - name: "negative amount in native minter config", - config: NewContractNativeMinterConfig(big.NewInt(3), admins, nil, - map[common.Address]*math.HexOrDecimal256{ - common.HexToAddress("0x01"): math.NewHexOrDecimal256(123), - common.HexToAddress("0x02"): math.NewHexOrDecimal256(-1), - }), - expectedError: "initial mint cannot contain invalid amount", - }, - { - name: "duplicate enableds in config in reward manager allowlist", - config: NewRewardManagerConfig(big.NewInt(3), admins, append(enableds, enableds[0]), nil), - expectedError: "duplicate address", - }, - { - name: "both reward mechanisms should not be activated at the same time in reward manager", - config: NewRewardManagerConfig(big.NewInt(3), admins, enableds, &InitialRewardConfig{ - AllowFeeRecipients: true, - RewardAddress: common.HexToAddress("0x01"), - }), - expectedError: ErrCannotEnableBothRewards.Error(), - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - require := require.New(t) - - err := tt.config.Verify() - if tt.expectedError == "" { - require.NoError(err) - } else { - require.ErrorContains(err, tt.expectedError) - } - }) - } -} - -func TestEqualTxAllowListConfig(t *testing.T) { - admins := []common.Address{{1}} - enableds := []common.Address{{2}} - tests := []struct { - name string - config StatefulPrecompileConfig - other StatefulPrecompileConfig - expected bool - }{ - { - name: "non-nil config and nil other", - config: NewTxAllowListConfig(big.NewInt(3), admins, enableds), - other: nil, - expected: false, - }, - { - name: "different type", - config: NewTxAllowListConfig(big.NewInt(3), admins, enableds), - other: NewContractDeployerAllowListConfig(big.NewInt(3), admins, enableds), - expected: false, - }, - { - name: "different admin", - config: NewTxAllowListConfig(big.NewInt(3), admins, enableds), - other: NewTxAllowListConfig(big.NewInt(3), []common.Address{{3}}, enableds), - expected: false, - }, - { - name: "different enabled", - config: NewTxAllowListConfig(big.NewInt(3), admins, enableds), - other: NewTxAllowListConfig(big.NewInt(3), admins, []common.Address{{3}}), - expected: false, - }, - { - name: "different timestamp", - config: NewTxAllowListConfig(big.NewInt(3), admins, enableds), - other: NewTxAllowListConfig(big.NewInt(4), admins, enableds), - expected: false, - }, - { - name: "same config", - config: NewTxAllowListConfig(big.NewInt(3), admins, enableds), - other: NewTxAllowListConfig(big.NewInt(3), admins, enableds), - expected: true, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - require := require.New(t) - - require.Equal(tt.expected, tt.config.Equal(tt.other)) - }) - } -} - -func TestEqualContractDeployerAllowListConfig(t *testing.T) { - admins := []common.Address{{1}} - enableds := []common.Address{{2}} - tests := []struct { - name string - config StatefulPrecompileConfig - other StatefulPrecompileConfig - expected bool - }{ - { - name: "non-nil config and nil other", - config: NewContractDeployerAllowListConfig(big.NewInt(3), admins, enableds), - other: nil, - expected: false, - }, - { - name: "different type", - config: NewContractDeployerAllowListConfig(big.NewInt(3), admins, enableds), - other: NewTxAllowListConfig(big.NewInt(3), admins, enableds), - expected: false, - }, - { - name: "different admin", - config: NewContractDeployerAllowListConfig(big.NewInt(3), admins, enableds), - other: NewContractDeployerAllowListConfig(big.NewInt(3), []common.Address{{3}}, enableds), - expected: false, - }, - { - name: "different enabled", - config: NewContractDeployerAllowListConfig(big.NewInt(3), admins, enableds), - other: NewContractDeployerAllowListConfig(big.NewInt(3), admins, []common.Address{{3}}), - expected: false, - }, - { - name: "different timestamp", - config: NewContractDeployerAllowListConfig(big.NewInt(3), admins, enableds), - other: NewContractDeployerAllowListConfig(big.NewInt(4), admins, enableds), - expected: false, - }, - { - name: "same config", - config: NewContractDeployerAllowListConfig(big.NewInt(3), admins, enableds), - other: NewContractDeployerAllowListConfig(big.NewInt(3), admins, enableds), - expected: true, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - require := require.New(t) - - require.Equal(tt.expected, tt.config.Equal(tt.other)) - }) - } -} - -func TestEqualContractNativeMinterConfig(t *testing.T) { - admins := []common.Address{{1}} - enableds := []common.Address{{2}} - tests := []struct { - name string - config StatefulPrecompileConfig - other StatefulPrecompileConfig - expected bool - }{ - { - name: "non-nil config and nil other", - config: NewContractNativeMinterConfig(big.NewInt(3), admins, enableds, nil), - other: nil, - expected: false, - }, - { - name: "different type", - config: NewContractNativeMinterConfig(big.NewInt(3), admins, enableds, nil), - other: NewTxAllowListConfig(big.NewInt(3), []common.Address{{1}}, []common.Address{{2}}), - expected: false, - }, - { - name: "different timestamps", - config: NewContractNativeMinterConfig(big.NewInt(3), admins, nil, nil), - other: NewContractNativeMinterConfig(big.NewInt(4), admins, nil, nil), - expected: false, - }, - { - name: "different enabled", - config: NewContractNativeMinterConfig(big.NewInt(3), admins, nil, nil), - other: NewContractNativeMinterConfig(big.NewInt(3), admins, enableds, nil), - expected: false, - }, - { - name: "different initial mint amounts", - config: NewContractNativeMinterConfig(big.NewInt(3), admins, nil, - map[common.Address]*math.HexOrDecimal256{ - common.HexToAddress("0x01"): math.NewHexOrDecimal256(1), - }), - other: NewContractNativeMinterConfig(big.NewInt(3), admins, nil, - map[common.Address]*math.HexOrDecimal256{ - common.HexToAddress("0x01"): math.NewHexOrDecimal256(2), - }), - expected: false, - }, - { - name: "different initial mint addresses", - config: NewContractNativeMinterConfig(big.NewInt(3), admins, nil, - map[common.Address]*math.HexOrDecimal256{ - common.HexToAddress("0x01"): math.NewHexOrDecimal256(1), - }), - other: NewContractNativeMinterConfig(big.NewInt(3), admins, nil, - map[common.Address]*math.HexOrDecimal256{ - common.HexToAddress("0x02"): math.NewHexOrDecimal256(1), - }), - expected: false, - }, - - { - name: "same config", - config: NewContractNativeMinterConfig(big.NewInt(3), admins, nil, - map[common.Address]*math.HexOrDecimal256{ - common.HexToAddress("0x01"): math.NewHexOrDecimal256(1), - }), - other: NewContractNativeMinterConfig(big.NewInt(3), admins, nil, - map[common.Address]*math.HexOrDecimal256{ - common.HexToAddress("0x01"): math.NewHexOrDecimal256(1), - }), - expected: true, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - require := require.New(t) - - require.Equal(tt.expected, tt.config.Equal(tt.other)) - }) - } -} - -func TestEqualFeeConfigManagerConfig(t *testing.T) { - admins := []common.Address{{1}} - enableds := []common.Address{{2}} - tests := []struct { - name string - config StatefulPrecompileConfig - other StatefulPrecompileConfig - expected bool - }{ - { - name: "non-nil config and nil other", - config: NewFeeManagerConfig(big.NewInt(3), admins, enableds, nil), - other: nil, - expected: false, - }, - { - name: "different type", - config: NewFeeManagerConfig(big.NewInt(3), admins, enableds, nil), - other: NewTxAllowListConfig(big.NewInt(3), []common.Address{{1}}, []common.Address{{2}}), - expected: false, - }, - { - name: "different timestamp", - config: NewFeeManagerConfig(big.NewInt(3), admins, nil, nil), - other: NewFeeManagerConfig(big.NewInt(4), admins, nil, nil), - expected: false, - }, - { - name: "different enabled", - config: NewFeeManagerConfig(big.NewInt(3), admins, nil, nil), - other: NewFeeManagerConfig(big.NewInt(3), admins, enableds, nil), - expected: false, - }, - { - name: "non-nil initial config and nil initial config", - config: NewFeeManagerConfig(big.NewInt(3), admins, nil, &validFeeConfig), - other: NewFeeManagerConfig(big.NewInt(3), admins, nil, nil), - expected: false, - }, - { - name: "different initial config", - config: NewFeeManagerConfig(big.NewInt(3), admins, nil, &validFeeConfig), - other: NewFeeManagerConfig(big.NewInt(3), admins, nil, - func() *commontype.FeeConfig { - c := validFeeConfig - c.GasLimit = big.NewInt(123) - return &c - }()), - expected: false, - }, - { - name: "same config", - config: NewFeeManagerConfig(big.NewInt(3), admins, nil, &validFeeConfig), - other: NewFeeManagerConfig(big.NewInt(3), admins, nil, &validFeeConfig), - expected: true, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - require := require.New(t) - - require.Equal(tt.expected, tt.config.Equal(tt.other)) - }) - } -} diff --git a/precompile/contract.go b/precompile/contract.go index ca12252ab0..596ea6dc00 100644 --- a/precompile/contract.go +++ b/precompile/contract.go @@ -5,68 +5,16 @@ package precompile import ( "fmt" - "math/big" - "github.com/ava-labs/avalanchego/snow" - "github.com/ava-labs/subnet-evm/commontype" "github.com/ethereum/go-ethereum/common" ) const ( - selectorLen = 4 + SelectorLen = 4 ) type RunStatefulPrecompileFunc func(accessibleState PrecompileAccessibleState, caller common.Address, addr common.Address, input []byte, suppliedGas uint64, readOnly bool) (ret []byte, remainingGas uint64, err error) -// PrecompileAccessibleState defines the interface exposed to stateful precompile contracts -type PrecompileAccessibleState interface { - GetStateDB() StateDB - GetBlockContext() BlockContext - GetSnowContext() *snow.Context - CallFromPrecompile(caller common.Address, addr common.Address, input []byte, gas uint64, value *big.Int) (ret []byte, leftOverGas uint64, err error) -} - -// BlockContext defines an interface that provides information to a stateful precompile -// about the block that activates the upgrade. The precompile can access this information -// to initialize its state. -type BlockContext interface { - Number() *big.Int - Timestamp() *big.Int -} - -// ChainContext defines an interface that provides information to a stateful precompile -// about the chain configuration. The precompile can access this information to initialize -// its state. -type ChainConfig interface { - // GetFeeConfig returns the original FeeConfig that was set in the genesis. - GetFeeConfig() commontype.FeeConfig - // AllowedFeeRecipients returns true if fee recipients are allowed in the genesis. - AllowedFeeRecipients() bool -} - -// StateDB is the interface for accessing EVM state -type StateDB interface { - GetState(common.Address, common.Hash) common.Hash - SetState(common.Address, common.Hash, common.Hash) - - SetCode(common.Address, []byte) - - SetNonce(common.Address, uint64) - GetNonce(common.Address) uint64 - - GetBalance(common.Address) *big.Int - AddBalance(common.Address, *big.Int) - SubBalance(common.Address, *big.Int) - - CreateAccount(common.Address) - Exist(common.Address) bool - - AddLog(addr common.Address, topics []common.Hash, data []byte, blockNumber uint64) - - Suicide(common.Address) bool - Finalise(deleteEmptyObjects bool) -} - // StatefulPrecompiledContract is the interface for executing a precompiled contract type StatefulPrecompiledContract interface { // Run executes the precompiled contract. @@ -126,13 +74,13 @@ func (s *statefulPrecompileWithFunctionSelectors) Run(accessibleState Precompile } // Otherwise, an unexpected input size will result in an error. - if len(input) < selectorLen { + if len(input) < SelectorLen { return nil, suppliedGas, fmt.Errorf("missing function selector to precompile - input length (%d)", len(input)) } // Use the function selector to grab the correct function - selector := input[:selectorLen] - functionInput := input[selectorLen:] + selector := input[:SelectorLen] + functionInput := input[SelectorLen:] function, ok := s.functions[string(selector)] if !ok { return nil, suppliedGas, fmt.Errorf("invalid function selector %#x", selector) diff --git a/precompile/contract_native_minter.go b/precompile/contract_native_minter.go deleted file mode 100644 index 92080157e2..0000000000 --- a/precompile/contract_native_minter.go +++ /dev/null @@ -1,227 +0,0 @@ -// (c) 2019-2020, Ava Labs, Inc. All rights reserved. -// See the file LICENSE for licensing terms. - -package precompile - -import ( - "encoding/json" - "errors" - "fmt" - "math/big" - - "github.com/ava-labs/subnet-evm/utils" - "github.com/ava-labs/subnet-evm/vmerrs" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/math" -) - -const ( - mintInputAddressSlot = iota - mintInputAmountSlot - - mintInputLen = common.HashLength + common.HashLength - - MintGasCost = 30_000 -) - -var ( - _ StatefulPrecompileConfig = &ContractNativeMinterConfig{} - // Singleton StatefulPrecompiledContract for minting native assets by permissioned callers. - ContractNativeMinterPrecompile StatefulPrecompiledContract = createNativeMinterPrecompile(ContractNativeMinterAddress) - - mintSignature = CalculateFunctionSelector("mintNativeCoin(address,uint256)") // address, amount - ErrCannotMint = errors.New("non-enabled cannot mint") -) - -// ContractNativeMinterConfig wraps [AllowListConfig] and uses it to implement the StatefulPrecompileConfig -// interface while adding in the ContractNativeMinter specific precompile address. -type ContractNativeMinterConfig struct { - AllowListConfig - UpgradeableConfig - InitialMint map[common.Address]*math.HexOrDecimal256 `json:"initialMint,omitempty"` // initial mint config to be immediately minted -} - -// NewContractNativeMinterConfig returns a config for a network upgrade at [blockTimestamp] that enables -// ContractNativeMinter with the given [admins] and [enableds] as members of the allowlist. Also mints balances according to [initialMint] when the upgrade activates. -func NewContractNativeMinterConfig(blockTimestamp *big.Int, admins []common.Address, enableds []common.Address, initialMint map[common.Address]*math.HexOrDecimal256) *ContractNativeMinterConfig { - return &ContractNativeMinterConfig{ - AllowListConfig: AllowListConfig{ - AllowListAdmins: admins, - EnabledAddresses: enableds, - }, - UpgradeableConfig: UpgradeableConfig{BlockTimestamp: blockTimestamp}, - InitialMint: initialMint, - } -} - -// NewDisableContractNativeMinterConfig returns config for a network upgrade at [blockTimestamp] -// that disables ContractNativeMinter. -func NewDisableContractNativeMinterConfig(blockTimestamp *big.Int) *ContractNativeMinterConfig { - return &ContractNativeMinterConfig{ - UpgradeableConfig: UpgradeableConfig{ - BlockTimestamp: blockTimestamp, - Disable: true, - }, - } -} - -// Address returns the address of the native minter contract. -func (c *ContractNativeMinterConfig) Address() common.Address { - return ContractNativeMinterAddress -} - -// Configure configures [state] with the desired admins based on [c]. -func (c *ContractNativeMinterConfig) Configure(_ ChainConfig, state StateDB, _ BlockContext) error { - for to, amount := range c.InitialMint { - if amount != nil { - bigIntAmount := (*big.Int)(amount) - state.AddBalance(to, bigIntAmount) - } - } - - return c.AllowListConfig.Configure(state, ContractNativeMinterAddress) -} - -// Contract returns the singleton stateful precompiled contract to be used for the native minter. -func (c *ContractNativeMinterConfig) Contract() StatefulPrecompiledContract { - return ContractNativeMinterPrecompile -} - -func (c *ContractNativeMinterConfig) Verify() error { - if err := c.AllowListConfig.Verify(); err != nil { - return err - } - // ensure that all of the initial mint values in the map are non-nil positive values - for addr, amount := range c.InitialMint { - if amount == nil { - return fmt.Errorf("initial mint cannot contain nil amount for address %s", addr) - } - bigIntAmount := (*big.Int)(amount) - if bigIntAmount.Sign() < 1 { - return fmt.Errorf("initial mint cannot contain invalid amount %v for address %s", bigIntAmount, addr) - } - } - return nil -} - -// Equal returns true if [s] is a [*ContractNativeMinterConfig] and it has been configured identical to [c]. -func (c *ContractNativeMinterConfig) Equal(s StatefulPrecompileConfig) bool { - // typecast before comparison - other, ok := (s).(*ContractNativeMinterConfig) - if !ok { - return false - } - eq := c.UpgradeableConfig.Equal(&other.UpgradeableConfig) && c.AllowListConfig.Equal(&other.AllowListConfig) - if !eq { - return false - } - - if len(c.InitialMint) != len(other.InitialMint) { - return false - } - - for address, amount := range c.InitialMint { - val, ok := other.InitialMint[address] - if !ok { - return false - } - bigIntAmount := (*big.Int)(amount) - bigIntVal := (*big.Int)(val) - if !utils.BigNumEqual(bigIntAmount, bigIntVal) { - return false - } - } - - return true -} - -// String returns a string representation of the ContractNativeMinterConfig. -func (c *ContractNativeMinterConfig) String() string { - bytes, _ := json.Marshal(c) - return string(bytes) -} - -// GetContractNativeMinterStatus returns the role of [address] for the minter list. -func GetContractNativeMinterStatus(stateDB StateDB, address common.Address) AllowListRole { - return GetAllowListStatus(stateDB, ContractNativeMinterAddress, address) -} - -// SetContractNativeMinterStatus sets the permissions of [address] to [role] for the -// minter list. assumes [role] has already been verified as valid. -func SetContractNativeMinterStatus(stateDB StateDB, address common.Address, role AllowListRole) { - SetAllowListRole(stateDB, ContractNativeMinterAddress, address, role) -} - -// PackMintInput packs [address] and [amount] into the appropriate arguments for minting operation. -// Assumes that [amount] can be represented by 32 bytes. -func PackMintInput(address common.Address, amount *big.Int) ([]byte, error) { - // function selector (4 bytes) + input(hash for address + hash for amount) - res := make([]byte, selectorLen+mintInputLen) - err := packOrderedHashesWithSelector(res, mintSignature, []common.Hash{ - address.Hash(), - common.BigToHash(amount), - }) - - return res, err -} - -// UnpackMintInput attempts to unpack [input] into the arguments to the mint precompile -// assumes that [input] does not include selector (omits first 4 bytes in PackMintInput) -func UnpackMintInput(input []byte) (common.Address, *big.Int, error) { - if len(input) != mintInputLen { - return common.Address{}, nil, fmt.Errorf("invalid input length for minting: %d", len(input)) - } - to := common.BytesToAddress(returnPackedHash(input, mintInputAddressSlot)) - assetAmount := new(big.Int).SetBytes(returnPackedHash(input, mintInputAmountSlot)) - return to, assetAmount, nil -} - -// mintNativeCoin checks if the caller is permissioned for minting operation. -// The execution function parses the [input] into native coin amount and receiver address. -func mintNativeCoin(accessibleState PrecompileAccessibleState, caller common.Address, addr common.Address, input []byte, suppliedGas uint64, readOnly bool) (ret []byte, remainingGas uint64, err error) { - if remainingGas, err = DeductGas(suppliedGas, MintGasCost); err != nil { - return nil, 0, err - } - - if readOnly { - return nil, remainingGas, vmerrs.ErrWriteProtection - } - - to, amount, err := UnpackMintInput(input) - if err != nil { - return nil, remainingGas, err - } - - stateDB := accessibleState.GetStateDB() - // Verify that the caller is in the allow list and therefore has the right to modify it - callerStatus := GetAllowListStatus(stateDB, ContractNativeMinterAddress, caller) - if !callerStatus.IsEnabled() { - return nil, remainingGas, fmt.Errorf("%w: %s", ErrCannotMint, caller) - } - - // if there is no address in the state, create one. - if !stateDB.Exist(to) { - stateDB.CreateAccount(to) - } - - stateDB.AddBalance(to, amount) - // Return an empty output and the remaining gas - return []byte{}, remainingGas, nil -} - -// createNativeMinterPrecompile returns a StatefulPrecompiledContract with R/W control of an allow list at [precompileAddr] and a native coin minter. -func createNativeMinterPrecompile(precompileAddr common.Address) StatefulPrecompiledContract { - enabledFuncs := CreateAllowListFunctions(precompileAddr) - - mintFunc := NewStatefulPrecompileFunction(mintSignature, mintNativeCoin) - - enabledFuncs = append(enabledFuncs, mintFunc) - // Construct the contract with no fallback function. - contract, err := NewStatefulPrecompileContract(nil, enabledFuncs) - // Change this to be returned as an error after refactoring this precompile - // to use the new precompile template. - if err != nil { - panic(err) - } - return contract -} diff --git a/precompile/contract_deployer_allow_list.go b/precompile/deployerallowlist/config.go similarity index 58% rename from precompile/contract_deployer_allow_list.go rename to precompile/deployerallowlist/config.go index 8b266f2768..34ce2ded8a 100644 --- a/precompile/contract_deployer_allow_list.go +++ b/precompile/deployerallowlist/config.go @@ -1,37 +1,34 @@ // (c) 2019-2020, Ava Labs, Inc. All rights reserved. // See the file LICENSE for licensing terms. -package precompile +package deployerallowlist import ( "encoding/json" "math/big" + "github.com/ava-labs/subnet-evm/precompile" "github.com/ethereum/go-ethereum/common" ) -var ( - _ StatefulPrecompileConfig = &ContractDeployerAllowListConfig{} - // Singleton StatefulPrecompiledContract for W/R access to the contract deployer allow list. - ContractDeployerAllowListPrecompile StatefulPrecompiledContract = createAllowListPrecompile(ContractDeployerAllowListAddress) -) +var _ precompile.StatefulPrecompileConfig = &ContractDeployerAllowListConfig{} // ContractDeployerAllowListConfig wraps [AllowListConfig] and uses it to implement the StatefulPrecompileConfig // interface while adding in the contract deployer specific precompile address. type ContractDeployerAllowListConfig struct { - AllowListConfig - UpgradeableConfig + precompile.AllowListConfig + precompile.UpgradeableConfig } // NewContractDeployerAllowListConfig returns a config for a network upgrade at [blockTimestamp] that enables // ContractDeployerAllowList with [admins] and [enableds] as members of the allowlist. func NewContractDeployerAllowListConfig(blockTimestamp *big.Int, admins []common.Address, enableds []common.Address) *ContractDeployerAllowListConfig { return &ContractDeployerAllowListConfig{ - AllowListConfig: AllowListConfig{ + AllowListConfig: precompile.AllowListConfig{ AllowListAdmins: admins, EnabledAddresses: enableds, }, - UpgradeableConfig: UpgradeableConfig{BlockTimestamp: blockTimestamp}, + UpgradeableConfig: precompile.UpgradeableConfig{BlockTimestamp: blockTimestamp}, } } @@ -39,7 +36,7 @@ func NewContractDeployerAllowListConfig(blockTimestamp *big.Int, admins []common // that disables ContractDeployerAllowList. func NewDisableContractDeployerAllowListConfig(blockTimestamp *big.Int) *ContractDeployerAllowListConfig { return &ContractDeployerAllowListConfig{ - UpgradeableConfig: UpgradeableConfig{ + UpgradeableConfig: precompile.UpgradeableConfig{ BlockTimestamp: blockTimestamp, Disable: true, }, @@ -48,21 +45,21 @@ func NewDisableContractDeployerAllowListConfig(blockTimestamp *big.Int) *Contrac // Address returns the address of the contract deployer allow list. func (c *ContractDeployerAllowListConfig) Address() common.Address { - return ContractDeployerAllowListAddress + return precompile.ContractDeployerAllowListAddress } // Configure configures [state] with the desired admins based on [c]. -func (c *ContractDeployerAllowListConfig) Configure(_ ChainConfig, state StateDB, _ BlockContext) error { - return c.AllowListConfig.Configure(state, ContractDeployerAllowListAddress) +func (c *ContractDeployerAllowListConfig) Configure(_ precompile.ChainConfig, state precompile.StateDB, _ precompile.BlockContext) error { + return c.AllowListConfig.Configure(state, precompile.ContractDeployerAllowListAddress) } // Contract returns the singleton stateful precompiled contract to be used for the allow list. -func (c *ContractDeployerAllowListConfig) Contract() StatefulPrecompiledContract { +func (c *ContractDeployerAllowListConfig) Contract() precompile.StatefulPrecompiledContract { return ContractDeployerAllowListPrecompile } // Equal returns true if [s] is a [*ContractDeployerAllowListConfig] and it has been configured identical to [c]. -func (c *ContractDeployerAllowListConfig) Equal(s StatefulPrecompileConfig) bool { +func (c *ContractDeployerAllowListConfig) Equal(s precompile.StatefulPrecompileConfig) bool { // typecast before comparison other, ok := (s).(*ContractDeployerAllowListConfig) if !ok { @@ -76,16 +73,3 @@ func (c *ContractDeployerAllowListConfig) String() string { bytes, _ := json.Marshal(c) return string(bytes) } - -// GetContractDeployerAllowListStatus returns the role of [address] for the contract deployer -// allow list. -func GetContractDeployerAllowListStatus(stateDB StateDB, address common.Address) AllowListRole { - return GetAllowListStatus(stateDB, ContractDeployerAllowListAddress, address) -} - -// SetContractDeployerAllowListStatus sets the permissions of [address] to [role] for the -// contract deployer allow list. -// assumes [role] has already been verified as valid. -func SetContractDeployerAllowListStatus(stateDB StateDB, address common.Address, role AllowListRole) { - SetAllowListRole(stateDB, ContractDeployerAllowListAddress, address, role) -} diff --git a/precompile/deployerallowlist/config_test.go b/precompile/deployerallowlist/config_test.go new file mode 100644 index 0000000000..2ffb0be77c --- /dev/null +++ b/precompile/deployerallowlist/config_test.go @@ -0,0 +1,95 @@ +// (c) 2019-2020, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package deployerallowlist + +import ( + "math/big" + "testing" + + "github.com/ava-labs/subnet-evm/precompile" + "github.com/ethereum/go-ethereum/common" + "github.com/stretchr/testify/require" +) + +func TestVerifyContractDeployerConfig(t *testing.T) { + admins := []common.Address{{1}} + tests := []struct { + name string + config precompile.StatefulPrecompileConfig + expectedError string + }{ + { + name: "invalid allow list config in deployer allowlist", + config: NewContractDeployerAllowListConfig(big.NewInt(3), admins, admins), + expectedError: "cannot set address", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + require := require.New(t) + + err := tt.config.Verify() + if tt.expectedError == "" { + require.NoError(err) + } else { + require.ErrorContains(err, tt.expectedError) + } + }) + } +} + +func TestEqualContractDeployerAllowListConfig(t *testing.T) { + admins := []common.Address{{1}} + enableds := []common.Address{{2}} + tests := []struct { + name string + config precompile.StatefulPrecompileConfig + other precompile.StatefulPrecompileConfig + expected bool + }{ + { + name: "non-nil config and nil other", + config: NewContractDeployerAllowListConfig(big.NewInt(3), admins, enableds), + other: nil, + expected: false, + }, + { + name: "different type", + config: NewContractDeployerAllowListConfig(big.NewInt(3), admins, enableds), + other: precompile.NewNoopStatefulPrecompileConfig(), + expected: false, + }, + { + name: "different admin", + config: NewContractDeployerAllowListConfig(big.NewInt(3), admins, enableds), + other: NewContractDeployerAllowListConfig(big.NewInt(3), []common.Address{{3}}, enableds), + expected: false, + }, + { + name: "different enabled", + config: NewContractDeployerAllowListConfig(big.NewInt(3), admins, enableds), + other: NewContractDeployerAllowListConfig(big.NewInt(3), admins, []common.Address{{3}}), + expected: false, + }, + { + name: "different timestamp", + config: NewContractDeployerAllowListConfig(big.NewInt(3), admins, enableds), + other: NewContractDeployerAllowListConfig(big.NewInt(4), admins, enableds), + expected: false, + }, + { + name: "same config", + config: NewContractDeployerAllowListConfig(big.NewInt(3), admins, enableds), + other: NewContractDeployerAllowListConfig(big.NewInt(3), admins, enableds), + expected: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + require := require.New(t) + + require.Equal(tt.expected, tt.config.Equal(tt.other)) + }) + } +} diff --git a/precompile/deployerallowlist/contract.go b/precompile/deployerallowlist/contract.go new file mode 100644 index 0000000000..df464452b3 --- /dev/null +++ b/precompile/deployerallowlist/contract.go @@ -0,0 +1,27 @@ +// (c) 2019-2020, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package deployerallowlist + +import ( + "github.com/ava-labs/subnet-evm/precompile" + "github.com/ethereum/go-ethereum/common" +) + +var ( + // Singleton StatefulPrecompiledContract for W/R access to the contract deployer allow list. + ContractDeployerAllowListPrecompile precompile.StatefulPrecompiledContract = precompile.CreateAllowListPrecompile(precompile.ContractDeployerAllowListAddress) +) + +// GetContractDeployerAllowListStatus returns the role of [address] for the contract deployer +// allow list. +func GetContractDeployerAllowListStatus(stateDB precompile.StateDB, address common.Address) precompile.AllowListRole { + return precompile.GetAllowListStatus(stateDB, precompile.ContractDeployerAllowListAddress, address) +} + +// SetContractDeployerAllowListStatus sets the permissions of [address] to [role] for the +// contract deployer allow list. +// assumes [role] has already been verified as valid. +func SetContractDeployerAllowListStatus(stateDB precompile.StateDB, address common.Address, role precompile.AllowListRole) { + precompile.SetAllowListRole(stateDB, precompile.ContractDeployerAllowListAddress, address, role) +} diff --git a/precompile/feemanager/config.go b/precompile/feemanager/config.go new file mode 100644 index 0000000000..8de349ca83 --- /dev/null +++ b/precompile/feemanager/config.go @@ -0,0 +1,109 @@ +// (c) 2019-2020, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package feemanager + +import ( + "encoding/json" + "fmt" + "math/big" + + "github.com/ava-labs/subnet-evm/commontype" + "github.com/ava-labs/subnet-evm/precompile" + "github.com/ethereum/go-ethereum/common" +) + +// FeeConfigManagerConfig wraps [AllowListConfig] and uses it to implement the StatefulPrecompileConfig +// interface while adding in the FeeConfigManager specific precompile address. +type FeeConfigManagerConfig struct { + precompile.AllowListConfig // Config for the fee config manager allow list + precompile.UpgradeableConfig + InitialFeeConfig *commontype.FeeConfig `json:"initialFeeConfig,omitempty"` // initial fee config to be immediately activated +} + +// NewFeeManagerConfig returns a config for a network upgrade at [blockTimestamp] that enables +// FeeConfigManager with the given [admins] and [enableds] as members of the allowlist with [initialConfig] as initial fee config if specified. +func NewFeeManagerConfig(blockTimestamp *big.Int, admins []common.Address, enableds []common.Address, initialConfig *commontype.FeeConfig) *FeeConfigManagerConfig { + return &FeeConfigManagerConfig{ + AllowListConfig: precompile.AllowListConfig{ + AllowListAdmins: admins, + EnabledAddresses: enableds, + }, + UpgradeableConfig: precompile.UpgradeableConfig{BlockTimestamp: blockTimestamp}, + InitialFeeConfig: initialConfig, + } +} + +// NewDisableFeeManagerConfig returns config for a network upgrade at [blockTimestamp] +// that disables FeeConfigManager. +func NewDisableFeeManagerConfig(blockTimestamp *big.Int) *FeeConfigManagerConfig { + return &FeeConfigManagerConfig{ + UpgradeableConfig: precompile.UpgradeableConfig{ + BlockTimestamp: blockTimestamp, + Disable: true, + }, + } +} + +// Address returns the address of the fee config manager contract. +func (c *FeeConfigManagerConfig) Address() common.Address { + return precompile.FeeConfigManagerAddress +} + +// Equal returns true if [s] is a [*FeeConfigManagerConfig] and it has been configured identical to [c]. +func (c *FeeConfigManagerConfig) Equal(s precompile.StatefulPrecompileConfig) bool { + // typecast before comparison + other, ok := (s).(*FeeConfigManagerConfig) + if !ok { + return false + } + eq := c.UpgradeableConfig.Equal(&other.UpgradeableConfig) && c.AllowListConfig.Equal(&other.AllowListConfig) + if !eq { + return false + } + + if c.InitialFeeConfig == nil { + return other.InitialFeeConfig == nil + } + + return c.InitialFeeConfig.Equal(other.InitialFeeConfig) +} + +// Configure configures [state] with the desired admins based on [c]. +func (c *FeeConfigManagerConfig) Configure(chainConfig precompile.ChainConfig, state precompile.StateDB, blockContext precompile.BlockContext) error { + // Store the initial fee config into the state when the fee config manager activates. + if c.InitialFeeConfig != nil { + if err := StoreFeeConfig(state, *c.InitialFeeConfig, blockContext); err != nil { + // This should not happen since we already checked this config with Verify() + return fmt.Errorf("cannot configure given initial fee config: %w", err) + } + } else { + if err := StoreFeeConfig(state, chainConfig.GetFeeConfig(), blockContext); err != nil { + // This should not happen since we already checked the chain config in the genesis creation. + return fmt.Errorf("cannot configure fee config in chain config: %w", err) + } + } + return c.AllowListConfig.Configure(state, precompile.FeeConfigManagerAddress) +} + +// Contract returns the singleton stateful precompiled contract to be used for the fee manager. +func (c *FeeConfigManagerConfig) Contract() precompile.StatefulPrecompiledContract { + return FeeConfigManagerPrecompile +} + +func (c *FeeConfigManagerConfig) Verify() error { + if err := c.AllowListConfig.Verify(); err != nil { + return err + } + if c.InitialFeeConfig == nil { + return nil + } + + return c.InitialFeeConfig.Verify() +} + +// String returns a string representation of the FeeConfigManagerConfig. +func (c *FeeConfigManagerConfig) String() string { + bytes, _ := json.Marshal(c) + return string(bytes) +} diff --git a/precompile/feemanager/config_test.go b/precompile/feemanager/config_test.go new file mode 100644 index 0000000000..ed45821d6a --- /dev/null +++ b/precompile/feemanager/config_test.go @@ -0,0 +1,128 @@ +// (c) 2022 Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package feemanager + +import ( + "math/big" + "testing" + + "github.com/ava-labs/subnet-evm/commontype" + "github.com/ava-labs/subnet-evm/precompile" + "github.com/ethereum/go-ethereum/common" + "github.com/stretchr/testify/require" +) + +var validFeeConfig = 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), +} + +func TestVerifyFeeManagerConfig(t *testing.T) { + admins := []common.Address{{1}} + tests := []struct { + name string + config precompile.StatefulPrecompileConfig + expectedError string + }{ + { + name: "invalid allow list config in fee manager allowlist", + config: NewFeeManagerConfig(big.NewInt(3), admins, admins, nil), + expectedError: "cannot set address", + }, + { + name: "invalid initial fee manager config", + config: NewFeeManagerConfig(big.NewInt(3), admins, nil, + &commontype.FeeConfig{ + GasLimit: big.NewInt(0), + }), + expectedError: "gasLimit = 0 cannot be less than or equal to 0", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + require := require.New(t) + + err := tt.config.Verify() + if tt.expectedError == "" { + require.NoError(err) + } else { + require.ErrorContains(err, tt.expectedError) + } + }) + } +} + +func TestEqualFeeConfigManagerConfig(t *testing.T) { + admins := []common.Address{{1}} + enableds := []common.Address{{2}} + tests := []struct { + name string + config precompile.StatefulPrecompileConfig + other precompile.StatefulPrecompileConfig + expected bool + }{ + { + name: "non-nil config and nil other", + config: NewFeeManagerConfig(big.NewInt(3), admins, enableds, nil), + other: nil, + expected: false, + }, + { + name: "different type", + config: NewFeeManagerConfig(big.NewInt(3), admins, enableds, nil), + other: precompile.NewNoopStatefulPrecompileConfig(), + expected: false, + }, + { + name: "different timestamp", + config: NewFeeManagerConfig(big.NewInt(3), admins, nil, nil), + other: NewFeeManagerConfig(big.NewInt(4), admins, nil, nil), + expected: false, + }, + { + name: "different enabled", + config: NewFeeManagerConfig(big.NewInt(3), admins, nil, nil), + other: NewFeeManagerConfig(big.NewInt(3), admins, enableds, nil), + expected: false, + }, + { + name: "non-nil initial config and nil initial config", + config: NewFeeManagerConfig(big.NewInt(3), admins, nil, &validFeeConfig), + other: NewFeeManagerConfig(big.NewInt(3), admins, nil, nil), + expected: false, + }, + { + name: "different initial config", + config: NewFeeManagerConfig(big.NewInt(3), admins, nil, &validFeeConfig), + other: NewFeeManagerConfig(big.NewInt(3), admins, nil, + func() *commontype.FeeConfig { + c := validFeeConfig + c.GasLimit = big.NewInt(123) + return &c + }()), + expected: false, + }, + { + name: "same config", + config: NewFeeManagerConfig(big.NewInt(3), admins, nil, &validFeeConfig), + other: NewFeeManagerConfig(big.NewInt(3), admins, nil, &validFeeConfig), + expected: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + require := require.New(t) + + require.Equal(tt.expected, tt.config.Equal(tt.other)) + }) + } +} diff --git a/precompile/fee_config_manager.go b/precompile/feemanager/contract.go similarity index 56% rename from precompile/fee_config_manager.go rename to precompile/feemanager/contract.go index 1cad22cb8e..996920203e 100644 --- a/precompile/fee_config_manager.go +++ b/precompile/feemanager/contract.go @@ -1,15 +1,15 @@ // (c) 2019-2020, Ava Labs, Inc. All rights reserved. // See the file LICENSE for licensing terms. -package precompile +package feemanager import ( - "encoding/json" "errors" "fmt" "math/big" "github.com/ava-labs/subnet-evm/commontype" + "github.com/ava-labs/subnet-evm/precompile" "github.com/ava-labs/subnet-evm/vmerrs" "github.com/ethereum/go-ethereum/common" ) @@ -32,130 +32,35 @@ const ( // [numFeeConfigField] fields in FeeConfig struct feeConfigInputLen = common.HashLength * numFeeConfigField - SetFeeConfigGasCost = WriteGasCostPerSlot * (numFeeConfigField + 1) // plus one for setting last changed at - GetFeeConfigGasCost = ReadGasCostPerSlot * numFeeConfigField - GetLastChangedAtGasCost = ReadGasCostPerSlot + SetFeeConfigGasCost = precompile.WriteGasCostPerSlot * (numFeeConfigField + 1) // plus one for setting last changed at + GetFeeConfigGasCost = precompile.ReadGasCostPerSlot * numFeeConfigField + GetLastChangedAtGasCost = precompile.ReadGasCostPerSlot ) var ( - _ StatefulPrecompileConfig = &FeeConfigManagerConfig{} + _ precompile.StatefulPrecompileConfig = &FeeConfigManagerConfig{} // Singleton StatefulPrecompiledContract for setting fee configs by permissioned callers. - FeeConfigManagerPrecompile StatefulPrecompiledContract = createFeeConfigManagerPrecompile(FeeConfigManagerAddress) + FeeConfigManagerPrecompile precompile.StatefulPrecompiledContract = createFeeConfigManagerPrecompile(precompile.FeeConfigManagerAddress) - setFeeConfigSignature = CalculateFunctionSelector("setFeeConfig(uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256)") - getFeeConfigSignature = CalculateFunctionSelector("getFeeConfig()") - getFeeConfigLastChangedAtSignature = CalculateFunctionSelector("getFeeConfigLastChangedAt()") + setFeeConfigSignature = precompile.CalculateFunctionSelector("setFeeConfig(uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256)") + getFeeConfigSignature = precompile.CalculateFunctionSelector("getFeeConfig()") + getFeeConfigLastChangedAtSignature = precompile.CalculateFunctionSelector("getFeeConfigLastChangedAt()") feeConfigLastChangedAtKey = common.Hash{'l', 'c', 'a'} ErrCannotChangeFee = errors.New("non-enabled cannot change fee config") ) -// FeeConfigManagerConfig wraps [AllowListConfig] and uses it to implement the StatefulPrecompileConfig -// interface while adding in the FeeConfigManager specific precompile address. -type FeeConfigManagerConfig struct { - AllowListConfig // Config for the fee config manager allow list - UpgradeableConfig - InitialFeeConfig *commontype.FeeConfig `json:"initialFeeConfig,omitempty"` // initial fee config to be immediately activated -} - -// NewFeeManagerConfig returns a config for a network upgrade at [blockTimestamp] that enables -// FeeConfigManager with the given [admins] and [enableds] as members of the allowlist with [initialConfig] as initial fee config if specified. -func NewFeeManagerConfig(blockTimestamp *big.Int, admins []common.Address, enableds []common.Address, initialConfig *commontype.FeeConfig) *FeeConfigManagerConfig { - return &FeeConfigManagerConfig{ - AllowListConfig: AllowListConfig{ - AllowListAdmins: admins, - EnabledAddresses: enableds, - }, - UpgradeableConfig: UpgradeableConfig{BlockTimestamp: blockTimestamp}, - InitialFeeConfig: initialConfig, - } -} - -// NewDisableFeeManagerConfig returns config for a network upgrade at [blockTimestamp] -// that disables FeeConfigManager. -func NewDisableFeeManagerConfig(blockTimestamp *big.Int) *FeeConfigManagerConfig { - return &FeeConfigManagerConfig{ - UpgradeableConfig: UpgradeableConfig{ - BlockTimestamp: blockTimestamp, - Disable: true, - }, - } -} - -// Address returns the address of the fee config manager contract. -func (c *FeeConfigManagerConfig) Address() common.Address { - return FeeConfigManagerAddress -} - -// Equal returns true if [s] is a [*FeeConfigManagerConfig] and it has been configured identical to [c]. -func (c *FeeConfigManagerConfig) Equal(s StatefulPrecompileConfig) bool { - // typecast before comparison - other, ok := (s).(*FeeConfigManagerConfig) - if !ok { - return false - } - eq := c.UpgradeableConfig.Equal(&other.UpgradeableConfig) && c.AllowListConfig.Equal(&other.AllowListConfig) - if !eq { - return false - } - - if c.InitialFeeConfig == nil { - return other.InitialFeeConfig == nil - } - - return c.InitialFeeConfig.Equal(other.InitialFeeConfig) -} - -// Configure configures [state] with the desired admins based on [c]. -func (c *FeeConfigManagerConfig) Configure(chainConfig ChainConfig, state StateDB, blockContext BlockContext) error { - // Store the initial fee config into the state when the fee config manager activates. - if c.InitialFeeConfig != nil { - if err := StoreFeeConfig(state, *c.InitialFeeConfig, blockContext); err != nil { - // This should not happen since we already checked this config with Verify() - return fmt.Errorf("cannot configure given initial fee config: %w", err) - } - } else { - if err := StoreFeeConfig(state, chainConfig.GetFeeConfig(), blockContext); err != nil { - // This should not happen since we already checked the chain config in the genesis creation. - return fmt.Errorf("cannot configure fee config in chain config: %w", err) - } - } - return c.AllowListConfig.Configure(state, FeeConfigManagerAddress) -} - -// Contract returns the singleton stateful precompiled contract to be used for the fee manager. -func (c *FeeConfigManagerConfig) Contract() StatefulPrecompiledContract { - return FeeConfigManagerPrecompile -} - -func (c *FeeConfigManagerConfig) Verify() error { - if err := c.AllowListConfig.Verify(); err != nil { - return err - } - if c.InitialFeeConfig == nil { - return nil - } - - return c.InitialFeeConfig.Verify() -} - -// String returns a string representation of the FeeConfigManagerConfig. -func (c *FeeConfigManagerConfig) String() string { - bytes, _ := json.Marshal(c) - return string(bytes) -} - // GetFeeConfigManagerStatus returns the role of [address] for the fee config manager list. -func GetFeeConfigManagerStatus(stateDB StateDB, address common.Address) AllowListRole { - return GetAllowListStatus(stateDB, FeeConfigManagerAddress, address) +func GetFeeConfigManagerStatus(stateDB precompile.StateDB, address common.Address) precompile.AllowListRole { + return precompile.GetAllowListStatus(stateDB, precompile.FeeConfigManagerAddress, address) } // SetFeeConfigManagerStatus sets the permissions of [address] to [role] for the // fee config manager list. assumes [role] has already been verified as valid. -func SetFeeConfigManagerStatus(stateDB StateDB, address common.Address, role AllowListRole) { - SetAllowListRole(stateDB, FeeConfigManagerAddress, address, role) +func SetFeeConfigManagerStatus(stateDB precompile.StateDB, address common.Address, role precompile.AllowListRole) { + precompile.SetAllowListRole(stateDB, precompile.FeeConfigManagerAddress, address, role) } // PackGetFeeConfigInput packs the getFeeConfig signature @@ -194,12 +99,12 @@ func packFeeConfigHelper(feeConfig commontype.FeeConfig, useSelector bool) ([]by if useSelector { res := make([]byte, len(setFeeConfigSignature)+feeConfigInputLen) - err := packOrderedHashesWithSelector(res, setFeeConfigSignature, hashes) + err := precompile.PackOrderedHashesWithSelector(res, setFeeConfigSignature, hashes) return res, err } res := make([]byte, len(hashes)*common.HashLength) - err := packOrderedHashes(res, hashes) + err := precompile.PackOrderedHashes(res, hashes) return res, err } @@ -212,7 +117,7 @@ func UnpackFeeConfigInput(input []byte) (commontype.FeeConfig, error) { feeConfig := commontype.FeeConfig{} for i := minFeeConfigFieldKey; i <= numFeeConfigField; i++ { listIndex := i - 1 - packedElement := returnPackedHash(input, listIndex) + packedElement := precompile.PackedHash(input, listIndex) switch i { case gasLimitKey: feeConfig.GasLimit = new(big.Int).SetBytes(packedElement) @@ -239,10 +144,10 @@ func UnpackFeeConfigInput(input []byte) (commontype.FeeConfig, error) { } // GetStoredFeeConfig returns fee config from contract storage in given state -func GetStoredFeeConfig(stateDB StateDB) commontype.FeeConfig { +func GetStoredFeeConfig(stateDB precompile.StateDB) commontype.FeeConfig { feeConfig := commontype.FeeConfig{} for i := minFeeConfigFieldKey; i <= numFeeConfigField; i++ { - val := stateDB.GetState(FeeConfigManagerAddress, common.Hash{byte(i)}) + val := stateDB.GetState(precompile.FeeConfigManagerAddress, common.Hash{byte(i)}) switch i { case gasLimitKey: feeConfig.GasLimit = new(big.Int).Set(val.Big()) @@ -268,14 +173,14 @@ func GetStoredFeeConfig(stateDB StateDB) commontype.FeeConfig { return feeConfig } -func GetFeeConfigLastChangedAt(stateDB StateDB) *big.Int { - val := stateDB.GetState(FeeConfigManagerAddress, feeConfigLastChangedAtKey) +func GetFeeConfigLastChangedAt(stateDB precompile.StateDB) *big.Int { + val := stateDB.GetState(precompile.FeeConfigManagerAddress, feeConfigLastChangedAtKey) return val.Big() } // StoreFeeConfig stores given [feeConfig] and block number in the [blockContext] to the [stateDB]. // A validation on [feeConfig] is done before storing. -func StoreFeeConfig(stateDB StateDB, feeConfig commontype.FeeConfig, blockContext BlockContext) error { +func StoreFeeConfig(stateDB precompile.StateDB, feeConfig commontype.FeeConfig, blockContext precompile.BlockContext) error { if err := feeConfig.Verify(); err != nil { return fmt.Errorf("cannot verify fee config: %w", err) } @@ -303,22 +208,22 @@ func StoreFeeConfig(stateDB StateDB, feeConfig commontype.FeeConfig, blockContex // This should never encounter an unknown fee config key panic(fmt.Sprintf("unknown fee config key: %d", i)) } - stateDB.SetState(FeeConfigManagerAddress, common.Hash{byte(i)}, input) + stateDB.SetState(precompile.FeeConfigManagerAddress, common.Hash{byte(i)}, input) } blockNumber := blockContext.Number() if blockNumber == nil { return fmt.Errorf("blockNumber cannot be nil") } - stateDB.SetState(FeeConfigManagerAddress, feeConfigLastChangedAtKey, common.BigToHash(blockNumber)) + stateDB.SetState(precompile.FeeConfigManagerAddress, feeConfigLastChangedAtKey, common.BigToHash(blockNumber)) return nil } // setFeeConfig checks if the caller has permissions to set the fee config. // The execution function parses [input] into FeeConfig structure and sets contract storage accordingly. -func setFeeConfig(accessibleState PrecompileAccessibleState, caller common.Address, addr common.Address, input []byte, suppliedGas uint64, readOnly bool) (ret []byte, remainingGas uint64, err error) { - if remainingGas, err = DeductGas(suppliedGas, SetFeeConfigGasCost); err != nil { +func setFeeConfig(accessibleState precompile.PrecompileAccessibleState, caller common.Address, addr common.Address, input []byte, suppliedGas uint64, readOnly bool) (ret []byte, remainingGas uint64, err error) { + if remainingGas, err = precompile.DeductGas(suppliedGas, SetFeeConfigGasCost); err != nil { return nil, 0, err } @@ -333,7 +238,7 @@ func setFeeConfig(accessibleState PrecompileAccessibleState, caller common.Addre stateDB := accessibleState.GetStateDB() // Verify that the caller is in the allow list and therefore has the right to modify it - callerStatus := GetAllowListStatus(stateDB, FeeConfigManagerAddress, caller) + callerStatus := precompile.GetAllowListStatus(stateDB, precompile.FeeConfigManagerAddress, caller) if !callerStatus.IsEnabled() { return nil, remainingGas, fmt.Errorf("%w: %s", ErrCannotChangeFee, caller) } @@ -348,8 +253,8 @@ func setFeeConfig(accessibleState PrecompileAccessibleState, caller common.Addre // getFeeConfig returns the stored fee config as an output. // The execution function reads the contract state for the stored fee config and returns the output. -func getFeeConfig(accessibleState PrecompileAccessibleState, caller common.Address, addr common.Address, input []byte, suppliedGas uint64, readOnly bool) (ret []byte, remainingGas uint64, err error) { - if remainingGas, err = DeductGas(suppliedGas, GetFeeConfigGasCost); err != nil { +func getFeeConfig(accessibleState precompile.PrecompileAccessibleState, caller common.Address, addr common.Address, input []byte, suppliedGas uint64, readOnly bool) (ret []byte, remainingGas uint64, err error) { + if remainingGas, err = precompile.DeductGas(suppliedGas, GetFeeConfigGasCost); err != nil { return nil, 0, err } @@ -366,8 +271,8 @@ func getFeeConfig(accessibleState PrecompileAccessibleState, caller common.Addre // getFeeConfigLastChangedAt returns the block number that fee config was last changed in. // The execution function reads the contract state for the stored block number and returns the output. -func getFeeConfigLastChangedAt(accessibleState PrecompileAccessibleState, caller common.Address, addr common.Address, input []byte, suppliedGas uint64, readOnly bool) (ret []byte, remainingGas uint64, err error) { - if remainingGas, err = DeductGas(suppliedGas, GetLastChangedAtGasCost); err != nil { +func getFeeConfigLastChangedAt(accessibleState precompile.PrecompileAccessibleState, caller common.Address, addr common.Address, input []byte, suppliedGas uint64, readOnly bool) (ret []byte, remainingGas uint64, err error) { + if remainingGas, err = precompile.DeductGas(suppliedGas, GetLastChangedAtGasCost); err != nil { return nil, 0, err } @@ -380,16 +285,16 @@ func getFeeConfigLastChangedAt(accessibleState PrecompileAccessibleState, caller // createFeeConfigManagerPrecompile returns a StatefulPrecompiledContract // with getters and setters for the chain's fee config. Access to the getters/setters // is controlled by an allow list for [precompileAddr]. -func createFeeConfigManagerPrecompile(precompileAddr common.Address) StatefulPrecompiledContract { - feeConfigManagerFunctions := CreateAllowListFunctions(precompileAddr) +func createFeeConfigManagerPrecompile(precompileAddr common.Address) precompile.StatefulPrecompiledContract { + feeConfigManagerFunctions := precompile.CreateAllowListFunctions(precompileAddr) - setFeeConfigFunc := NewStatefulPrecompileFunction(setFeeConfigSignature, setFeeConfig) - getFeeConfigFunc := NewStatefulPrecompileFunction(getFeeConfigSignature, getFeeConfig) - getFeeConfigLastChangedAtFunc := NewStatefulPrecompileFunction(getFeeConfigLastChangedAtSignature, getFeeConfigLastChangedAt) + setFeeConfigFunc := precompile.NewStatefulPrecompileFunction(setFeeConfigSignature, setFeeConfig) + getFeeConfigFunc := precompile.NewStatefulPrecompileFunction(getFeeConfigSignature, getFeeConfig) + getFeeConfigLastChangedAtFunc := precompile.NewStatefulPrecompileFunction(getFeeConfigLastChangedAtSignature, getFeeConfigLastChangedAt) feeConfigManagerFunctions = append(feeConfigManagerFunctions, setFeeConfigFunc, getFeeConfigFunc, getFeeConfigLastChangedAtFunc) // Construct the contract with no fallback function. - contract, err := NewStatefulPrecompileContract(nil, feeConfigManagerFunctions) + contract, err := precompile.NewStatefulPrecompileContract(nil, feeConfigManagerFunctions) // TODO Change this to be returned as an error after refactoring this precompile // to use the new precompile template. if err != nil { diff --git a/precompile/interface.go b/precompile/interface.go new file mode 100644 index 0000000000..82be0f749a --- /dev/null +++ b/precompile/interface.go @@ -0,0 +1,61 @@ +// (c) 2019-2020, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package precompile + +import ( + "math/big" + + "github.com/ava-labs/avalanchego/snow" + "github.com/ava-labs/subnet-evm/commontype" + "github.com/ethereum/go-ethereum/common" +) + +// PrecompileAccessibleState defines the interface exposed to stateful precompile contracts +type PrecompileAccessibleState interface { + GetStateDB() StateDB + GetBlockContext() BlockContext + GetSnowContext() *snow.Context + CallFromPrecompile(caller common.Address, addr common.Address, input []byte, gas uint64, value *big.Int) (ret []byte, leftOverGas uint64, err error) +} + +// BlockContext defines an interface that provides information to a stateful precompile +// about the block that activates the upgrade. The precompile can access this information +// to initialize its state. +type BlockContext interface { + Number() *big.Int + Timestamp() *big.Int +} + +// ChainContext defines an interface that provides information to a stateful precompile +// about the chain configuration. The precompile can access this information to initialize +// its state. +type ChainConfig interface { + // GetFeeConfig returns the original FeeConfig that was set in the genesis. + GetFeeConfig() commontype.FeeConfig + // AllowedFeeRecipients returns true if fee recipients are allowed in the genesis. + AllowedFeeRecipients() bool +} + +// StateDB is the interface for accessing EVM state +type StateDB interface { + GetState(common.Address, common.Hash) common.Hash + SetState(common.Address, common.Hash, common.Hash) + + SetCode(common.Address, []byte) + + SetNonce(common.Address, uint64) + GetNonce(common.Address) uint64 + + GetBalance(common.Address) *big.Int + AddBalance(common.Address, *big.Int) + SubBalance(common.Address, *big.Int) + + CreateAccount(common.Address) + Exist(common.Address) bool + + AddLog(addr common.Address, topics []common.Hash, data []byte, blockNumber uint64) + + Suicide(common.Address) bool + Finalise(deleteEmptyObjects bool) +} diff --git a/precompile/mock_interface.go b/precompile/mock_interface.go new file mode 100644 index 0000000000..4d6ca13281 --- /dev/null +++ b/precompile/mock_interface.go @@ -0,0 +1,115 @@ +// (c) 2019-2020, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package precompile + +import ( + "math/big" + + "github.com/ava-labs/avalanchego/snow" + "github.com/ava-labs/subnet-evm/commontype" + "github.com/ethereum/go-ethereum/common" +) + +// TODO: replace with gomock library + +var ( + _ BlockContext = &mockBlockContext{} + _ PrecompileAccessibleState = &mockAccessibleState{} + _ ChainConfig = &mockChainConfig{} + _ StatefulPrecompileConfig = &noopStatefulPrecompileConfig{} +) + +type mockBlockContext struct { + blockNumber *big.Int + timestamp uint64 +} + +func NewMockBlockContext(blockNumber *big.Int, timestamp uint64) *mockBlockContext { + return &mockBlockContext{ + blockNumber: blockNumber, + timestamp: timestamp, + } +} + +func (mb *mockBlockContext) Number() *big.Int { return mb.blockNumber } +func (mb *mockBlockContext) Timestamp() *big.Int { return new(big.Int).SetUint64(mb.timestamp) } + +type mockAccessibleState struct { + state StateDB + blockContext *mockBlockContext + snowContext *snow.Context +} + +func NewMockAccessibleState(state StateDB, blockContext *mockBlockContext, snowContext *snow.Context) *mockAccessibleState { + return &mockAccessibleState{ + state: state, + blockContext: blockContext, + snowContext: snowContext, + } +} + +func (m *mockAccessibleState) GetStateDB() StateDB { return m.state } + +func (m *mockAccessibleState) GetBlockContext() BlockContext { return m.blockContext } + +func (m *mockAccessibleState) GetSnowContext() *snow.Context { return m.snowContext } + +func (m *mockAccessibleState) CallFromPrecompile(caller common.Address, addr common.Address, input []byte, gas uint64, value *big.Int) (ret []byte, leftOverGas uint64, err error) { + return nil, 0, nil +} + +type mockChainConfig struct { + feeConfig commontype.FeeConfig + allowedFeeRecipients bool +} + +func NewMockChainConfig(feeConfig commontype.FeeConfig, allowedFeeRecipients bool) *mockChainConfig { + return &mockChainConfig{ + feeConfig: feeConfig, + allowedFeeRecipients: allowedFeeRecipients, + } +} + +func (m *mockChainConfig) GetFeeConfig() commontype.FeeConfig { return m.feeConfig } + +func (m *mockChainConfig) AllowedFeeRecipients() bool { return m.allowedFeeRecipients } + +type noopStatefulPrecompileConfig struct { +} + +func NewNoopStatefulPrecompileConfig() *noopStatefulPrecompileConfig { + return &noopStatefulPrecompileConfig{} +} + +func (n *noopStatefulPrecompileConfig) Address() common.Address { + return common.Address{} +} + +func (n *noopStatefulPrecompileConfig) Timestamp() *big.Int { + return new(big.Int) +} + +func (n *noopStatefulPrecompileConfig) IsDisabled() bool { + return false +} + +func (n *noopStatefulPrecompileConfig) Equal(StatefulPrecompileConfig) bool { + return false +} + +func (n *noopStatefulPrecompileConfig) Verify() error { + return nil +} + +func (n *noopStatefulPrecompileConfig) Configure(ChainConfig, StateDB, BlockContext) error { + return nil +} + +func (n *noopStatefulPrecompileConfig) Contract() StatefulPrecompiledContract { + return nil +} + +func (n *noopStatefulPrecompileConfig) String() string { + return "" +} diff --git a/precompile/nativeminter/config.go b/precompile/nativeminter/config.go new file mode 100644 index 0000000000..9ba6644b6e --- /dev/null +++ b/precompile/nativeminter/config.go @@ -0,0 +1,125 @@ +// (c) 2019-2020, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package nativeminter + +import ( + "encoding/json" + "fmt" + "math/big" + + "github.com/ava-labs/subnet-evm/precompile" + "github.com/ava-labs/subnet-evm/utils" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/math" +) + +var _ precompile.StatefulPrecompileConfig = &ContractNativeMinterConfig{} + +// ContractNativeMinterConfig wraps [AllowListConfig] and uses it to implement the StatefulPrecompileConfig +// interface while adding in the ContractNativeMinter specific precompile address. +type ContractNativeMinterConfig struct { + precompile.AllowListConfig + precompile.UpgradeableConfig + InitialMint map[common.Address]*math.HexOrDecimal256 `json:"initialMint,omitempty"` // initial mint config to be immediately minted +} + +// NewContractNativeMinterConfig returns a config for a network upgrade at [blockTimestamp] that enables +// ContractNativeMinter with the given [admins] and [enableds] as members of the allowlist. Also mints balances according to [initialMint] when the upgrade activates. +func NewContractNativeMinterConfig(blockTimestamp *big.Int, admins []common.Address, enableds []common.Address, initialMint map[common.Address]*math.HexOrDecimal256) *ContractNativeMinterConfig { + return &ContractNativeMinterConfig{ + AllowListConfig: precompile.AllowListConfig{ + AllowListAdmins: admins, + EnabledAddresses: enableds, + }, + UpgradeableConfig: precompile.UpgradeableConfig{BlockTimestamp: blockTimestamp}, + InitialMint: initialMint, + } +} + +// NewDisableContractNativeMinterConfig returns config for a network upgrade at [blockTimestamp] +// that disables ContractNativeMinter. +func NewDisableContractNativeMinterConfig(blockTimestamp *big.Int) *ContractNativeMinterConfig { + return &ContractNativeMinterConfig{ + UpgradeableConfig: precompile.UpgradeableConfig{ + BlockTimestamp: blockTimestamp, + Disable: true, + }, + } +} + +// Address returns the address of the native minter contract. +func (c *ContractNativeMinterConfig) Address() common.Address { + return precompile.ContractNativeMinterAddress +} + +// Configure configures [state] with the desired admins based on [c]. +func (c *ContractNativeMinterConfig) Configure(_ precompile.ChainConfig, state precompile.StateDB, _ precompile.BlockContext) error { + for to, amount := range c.InitialMint { + if amount != nil { + bigIntAmount := (*big.Int)(amount) + state.AddBalance(to, bigIntAmount) + } + } + + return c.AllowListConfig.Configure(state, precompile.ContractNativeMinterAddress) +} + +// Contract returns the singleton stateful precompiled contract to be used for the native minter. +func (c *ContractNativeMinterConfig) Contract() precompile.StatefulPrecompiledContract { + return ContractNativeMinterPrecompile +} + +func (c *ContractNativeMinterConfig) Verify() error { + if err := c.AllowListConfig.Verify(); err != nil { + return err + } + // ensure that all of the initial mint values in the map are non-nil positive values + for addr, amount := range c.InitialMint { + if amount == nil { + return fmt.Errorf("initial mint cannot contain nil amount for address %s", addr) + } + bigIntAmount := (*big.Int)(amount) + if bigIntAmount.Sign() < 1 { + return fmt.Errorf("initial mint cannot contain invalid amount %v for address %s", bigIntAmount, addr) + } + } + return nil +} + +// Equal returns true if [s] is a [*ContractNativeMinterConfig] and it has been configured identical to [c]. +func (c *ContractNativeMinterConfig) Equal(s precompile.StatefulPrecompileConfig) bool { + // typecast before comparison + other, ok := (s).(*ContractNativeMinterConfig) + if !ok { + return false + } + eq := c.UpgradeableConfig.Equal(&other.UpgradeableConfig) && c.AllowListConfig.Equal(&other.AllowListConfig) + if !eq { + return false + } + + if len(c.InitialMint) != len(other.InitialMint) { + return false + } + + for address, amount := range c.InitialMint { + val, ok := other.InitialMint[address] + if !ok { + return false + } + bigIntAmount := (*big.Int)(amount) + bigIntVal := (*big.Int)(val) + if !utils.BigNumEqual(bigIntAmount, bigIntVal) { + return false + } + } + + return true +} + +// String returns a string representation of the ContractNativeMinterConfig. +func (c *ContractNativeMinterConfig) String() string { + bytes, _ := json.Marshal(c) + return string(bytes) +} diff --git a/precompile/nativeminter/config_test.go b/precompile/nativeminter/config_test.go new file mode 100644 index 0000000000..99c87f4aad --- /dev/null +++ b/precompile/nativeminter/config_test.go @@ -0,0 +1,150 @@ +// (c) 2019-2020, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package nativeminter + +import ( + "math/big" + "testing" + + "github.com/ava-labs/subnet-evm/precompile" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/math" + "github.com/stretchr/testify/require" +) + +func TestVerifyContractNativeMinterConfig(t *testing.T) { + admins := []common.Address{{1}} + enableds := []common.Address{{2}} + tests := []struct { + name string + config precompile.StatefulPrecompileConfig + expectedError string + }{ + { + name: "invalid allow list config in native minter allowlist", + config: NewContractNativeMinterConfig(big.NewInt(3), admins, admins, nil), + expectedError: "cannot set address", + }, + { + name: "duplicate admins in config in native minter allowlist", + config: NewContractNativeMinterConfig(big.NewInt(3), append(admins, admins[0]), enableds, nil), + expectedError: "duplicate address", + }, + { + name: "duplicate enableds in config in native minter allowlist", + config: NewContractNativeMinterConfig(big.NewInt(3), admins, append(enableds, enableds[0]), nil), + expectedError: "duplicate address", + }, + { + name: "nil amount in native minter config", + config: NewContractNativeMinterConfig(big.NewInt(3), admins, nil, + map[common.Address]*math.HexOrDecimal256{ + common.HexToAddress("0x01"): math.NewHexOrDecimal256(123), + common.HexToAddress("0x02"): nil, + }), + expectedError: "initial mint cannot contain nil", + }, + { + name: "negative amount in native minter config", + config: NewContractNativeMinterConfig(big.NewInt(3), admins, nil, + map[common.Address]*math.HexOrDecimal256{ + common.HexToAddress("0x01"): math.NewHexOrDecimal256(123), + common.HexToAddress("0x02"): math.NewHexOrDecimal256(-1), + }), + expectedError: "initial mint cannot contain invalid amount", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + require := require.New(t) + + err := tt.config.Verify() + if tt.expectedError == "" { + require.NoError(err) + } else { + require.ErrorContains(err, tt.expectedError) + } + }) + } +} + +func TestEqualContractNativeMinterConfig(t *testing.T) { + admins := []common.Address{{1}} + enableds := []common.Address{{2}} + tests := []struct { + name string + config precompile.StatefulPrecompileConfig + other precompile.StatefulPrecompileConfig + expected bool + }{ + { + name: "non-nil config and nil other", + config: NewContractNativeMinterConfig(big.NewInt(3), admins, enableds, nil), + other: nil, + expected: false, + }, + { + name: "different type", + config: NewContractNativeMinterConfig(big.NewInt(3), admins, enableds, nil), + other: precompile.NewNoopStatefulPrecompileConfig(), + expected: false, + }, + { + name: "different timestamps", + config: NewContractNativeMinterConfig(big.NewInt(3), admins, nil, nil), + other: NewContractNativeMinterConfig(big.NewInt(4), admins, nil, nil), + expected: false, + }, + { + name: "different enabled", + config: NewContractNativeMinterConfig(big.NewInt(3), admins, nil, nil), + other: NewContractNativeMinterConfig(big.NewInt(3), admins, enableds, nil), + expected: false, + }, + { + name: "different initial mint amounts", + config: NewContractNativeMinterConfig(big.NewInt(3), admins, nil, + map[common.Address]*math.HexOrDecimal256{ + common.HexToAddress("0x01"): math.NewHexOrDecimal256(1), + }), + other: NewContractNativeMinterConfig(big.NewInt(3), admins, nil, + map[common.Address]*math.HexOrDecimal256{ + common.HexToAddress("0x01"): math.NewHexOrDecimal256(2), + }), + expected: false, + }, + { + name: "different initial mint addresses", + config: NewContractNativeMinterConfig(big.NewInt(3), admins, nil, + map[common.Address]*math.HexOrDecimal256{ + common.HexToAddress("0x01"): math.NewHexOrDecimal256(1), + }), + other: NewContractNativeMinterConfig(big.NewInt(3), admins, nil, + map[common.Address]*math.HexOrDecimal256{ + common.HexToAddress("0x02"): math.NewHexOrDecimal256(1), + }), + expected: false, + }, + + { + name: "same config", + config: NewContractNativeMinterConfig(big.NewInt(3), admins, nil, + map[common.Address]*math.HexOrDecimal256{ + common.HexToAddress("0x01"): math.NewHexOrDecimal256(1), + }), + other: NewContractNativeMinterConfig(big.NewInt(3), admins, nil, + map[common.Address]*math.HexOrDecimal256{ + common.HexToAddress("0x01"): math.NewHexOrDecimal256(1), + }), + expected: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + require := require.New(t) + + require.Equal(tt.expected, tt.config.Equal(tt.other)) + }) + } +} diff --git a/precompile/nativeminter/contract_native_minter.go b/precompile/nativeminter/contract_native_minter.go new file mode 100644 index 0000000000..aa3d19eedb --- /dev/null +++ b/precompile/nativeminter/contract_native_minter.go @@ -0,0 +1,116 @@ +// (c) 2019-2020, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package nativeminter + +import ( + "errors" + "fmt" + "math/big" + + "github.com/ava-labs/subnet-evm/precompile" + "github.com/ava-labs/subnet-evm/vmerrs" + "github.com/ethereum/go-ethereum/common" +) + +const ( + mintInputAddressSlot = iota + mintInputAmountSlot + + mintInputLen = common.HashLength + common.HashLength + + MintGasCost = 30_000 +) + +var ( + // Singleton StatefulPrecompiledContract for minting native assets by permissioned callers. + ContractNativeMinterPrecompile precompile.StatefulPrecompiledContract = createNativeMinterPrecompile(precompile.ContractNativeMinterAddress) + + mintSignature = precompile.CalculateFunctionSelector("mintNativeCoin(address,uint256)") // address, amount + ErrCannotMint = errors.New("non-enabled cannot mint") +) + +// GetContractNativeMinterStatus returns the role of [address] for the minter list. +func GetContractNativeMinterStatus(stateDB precompile.StateDB, address common.Address) precompile.AllowListRole { + return precompile.GetAllowListStatus(stateDB, precompile.ContractNativeMinterAddress, address) +} + +// SetContractNativeMinterStatus sets the permissions of [address] to [role] for the +// minter list. assumes [role] has already been verified as valid. +func SetContractNativeMinterStatus(stateDB precompile.StateDB, address common.Address, role precompile.AllowListRole) { + precompile.SetAllowListRole(stateDB, precompile.ContractNativeMinterAddress, address, role) +} + +// PackMintInput packs [address] and [amount] into the appropriate arguments for minting operation. +// Assumes that [amount] can be represented by 32 bytes. +func PackMintInput(address common.Address, amount *big.Int) ([]byte, error) { + // function selector (4 bytes) + input(hash for address + hash for amount) + res := make([]byte, precompile.SelectorLen+mintInputLen) + err := precompile.PackOrderedHashesWithSelector(res, mintSignature, []common.Hash{ + address.Hash(), + common.BigToHash(amount), + }) + + return res, err +} + +// UnpackMintInput attempts to unpack [input] into the arguments to the mint precompile +// assumes that [input] does not include selector (omits first 4 bytes in PackMintInput) +func UnpackMintInput(input []byte) (common.Address, *big.Int, error) { + if len(input) != mintInputLen { + return common.Address{}, nil, fmt.Errorf("invalid input length for minting: %d", len(input)) + } + to := common.BytesToAddress(precompile.PackedHash(input, mintInputAddressSlot)) + assetAmount := new(big.Int).SetBytes(precompile.PackedHash(input, mintInputAmountSlot)) + return to, assetAmount, nil +} + +// mintNativeCoin checks if the caller is permissioned for minting operation. +// The execution function parses the [input] into native coin amount and receiver address. +func mintNativeCoin(accessibleState precompile.PrecompileAccessibleState, caller common.Address, addr common.Address, input []byte, suppliedGas uint64, readOnly bool) (ret []byte, remainingGas uint64, err error) { + if remainingGas, err = precompile.DeductGas(suppliedGas, MintGasCost); err != nil { + return nil, 0, err + } + + if readOnly { + return nil, remainingGas, vmerrs.ErrWriteProtection + } + + to, amount, err := UnpackMintInput(input) + if err != nil { + return nil, remainingGas, err + } + + stateDB := accessibleState.GetStateDB() + // Verify that the caller is in the allow list and therefore has the right to modify it + callerStatus := precompile.GetAllowListStatus(stateDB, precompile.ContractNativeMinterAddress, caller) + if !callerStatus.IsEnabled() { + return nil, remainingGas, fmt.Errorf("%w: %s", ErrCannotMint, caller) + } + + // if there is no address in the state, create one. + if !stateDB.Exist(to) { + stateDB.CreateAccount(to) + } + + stateDB.AddBalance(to, amount) + // Return an empty output and the remaining gas + return []byte{}, remainingGas, nil +} + +// createNativeMinterPrecompile returns a StatefulPrecompiledContract with R/W control of an allow list at [precompileAddr] and a native coin minter. +func createNativeMinterPrecompile(precompileAddr common.Address) precompile.StatefulPrecompiledContract { + enabledFuncs := precompile.CreateAllowListFunctions(precompileAddr) + + mintFunc := precompile.NewStatefulPrecompileFunction(mintSignature, mintNativeCoin) + + enabledFuncs = append(enabledFuncs, mintFunc) + // Construct the contract with no fallback function. + contract, err := precompile.NewStatefulPrecompileContract(nil, enabledFuncs) + // Change this to be returned as an error after refactoring this precompile + // to use the new precompile template. + if err != nil { + panic(err) + } + return contract +} diff --git a/precompile/rewardmanager/config_test.go b/precompile/rewardmanager/config_test.go index 516496876a..7e5fb5c19f 100644 --- a/precompile/rewardmanager/config_test.go +++ b/precompile/rewardmanager/config_test.go @@ -12,7 +12,7 @@ import ( "github.com/stretchr/testify/require" ) -func TestVerifyPrecompileUpgrades(t *testing.T) { +func TestVerifyRewardManagerConfig(t *testing.T) { admins := []common.Address{{1}} enableds := []common.Address{{2}} tests := []struct { @@ -66,7 +66,7 @@ func TestEqualRewardManagerConfig(t *testing.T) { { name: "different type", config: NewRewardManagerConfig(big.NewInt(3), admins, enableds, nil), - other: precompile.NewTxAllowListConfig(big.NewInt(3), []common.Address{{1}}, []common.Address{{2}}), + other: precompile.NewNoopStatefulPrecompileConfig(), expected: false, }, { diff --git a/precompile/stateful_precompile_config.go b/precompile/stateful_precompile_config.go index 6955b8d448..3a293cbb5f 100644 --- a/precompile/stateful_precompile_config.go +++ b/precompile/stateful_precompile_config.go @@ -23,6 +23,8 @@ type StatefulPrecompileConfig interface { IsDisabled() bool // Equal returns true if the provided argument configures the same precompile with the same parameters. Equal(StatefulPrecompileConfig) bool + // Verify is called on startup and an error is treated as fatal. Configure can assume the Config has passed verification. + Verify() error // Configure is called on the first block where the stateful precompile should be enabled. // This allows the stateful precompile to configure its own state via [StateDB] and [BlockContext] as necessary. // This function must be deterministic since it will impact the EVM state. If a change to the @@ -36,8 +38,6 @@ type StatefulPrecompileConfig interface { // Contract returns a thread-safe singleton that can be used as the StatefulPrecompiledContract when // this config is enabled. Contract() StatefulPrecompiledContract - // Verify is called on startup and an error is treated as fatal. Configure can assume the Config has passed verification. - Verify() error fmt.Stringer } diff --git a/precompile/tx_allow_list.go b/precompile/txallowlist/config.go similarity index 57% rename from precompile/tx_allow_list.go rename to precompile/txallowlist/config.go index d5a41ccdc2..0551835405 100644 --- a/precompile/tx_allow_list.go +++ b/precompile/txallowlist/config.go @@ -1,40 +1,36 @@ // (c) 2019-2020, Ava Labs, Inc. All rights reserved. // See the file LICENSE for licensing terms. -package precompile +package txallowlist import ( "encoding/json" - "errors" "math/big" + "github.com/ava-labs/subnet-evm/precompile" "github.com/ethereum/go-ethereum/common" ) var ( - _ StatefulPrecompileConfig = &TxAllowListConfig{} - // Singleton StatefulPrecompiledContract for W/R access to the contract deployer allow list. - TxAllowListPrecompile StatefulPrecompiledContract = createAllowListPrecompile(TxAllowListAddress) - - ErrSenderAddressNotAllowListed = errors.New("cannot issue transaction from non-allow listed address") + _ precompile.StatefulPrecompileConfig = &TxAllowListConfig{} ) // TxAllowListConfig wraps [AllowListConfig] and uses it to implement the StatefulPrecompileConfig // interface while adding in the TxAllowList specific precompile address. type TxAllowListConfig struct { - AllowListConfig - UpgradeableConfig + precompile.AllowListConfig + precompile.UpgradeableConfig } // NewTxAllowListConfig returns a config for a network upgrade at [blockTimestamp] that enables // TxAllowList with the given [admins] and [enableds] as members of the allowlist. func NewTxAllowListConfig(blockTimestamp *big.Int, admins []common.Address, enableds []common.Address) *TxAllowListConfig { return &TxAllowListConfig{ - AllowListConfig: AllowListConfig{ + AllowListConfig: precompile.AllowListConfig{ AllowListAdmins: admins, EnabledAddresses: enableds, }, - UpgradeableConfig: UpgradeableConfig{BlockTimestamp: blockTimestamp}, + UpgradeableConfig: precompile.UpgradeableConfig{BlockTimestamp: blockTimestamp}, } } @@ -42,7 +38,7 @@ func NewTxAllowListConfig(blockTimestamp *big.Int, admins []common.Address, enab // that disables TxAllowList. func NewDisableTxAllowListConfig(blockTimestamp *big.Int) *TxAllowListConfig { return &TxAllowListConfig{ - UpgradeableConfig: UpgradeableConfig{ + UpgradeableConfig: precompile.UpgradeableConfig{ BlockTimestamp: blockTimestamp, Disable: true, }, @@ -51,21 +47,21 @@ func NewDisableTxAllowListConfig(blockTimestamp *big.Int) *TxAllowListConfig { // Address returns the address of the contract deployer allow list. func (c *TxAllowListConfig) Address() common.Address { - return TxAllowListAddress + return precompile.TxAllowListAddress } // Configure configures [state] with the desired admins based on [c]. -func (c *TxAllowListConfig) Configure(_ ChainConfig, state StateDB, _ BlockContext) error { - return c.AllowListConfig.Configure(state, TxAllowListAddress) +func (c *TxAllowListConfig) Configure(_ precompile.ChainConfig, state precompile.StateDB, _ precompile.BlockContext) error { + return c.AllowListConfig.Configure(state, precompile.TxAllowListAddress) } // Contract returns the singleton stateful precompiled contract to be used for the allow list. -func (c *TxAllowListConfig) Contract() StatefulPrecompiledContract { +func (c *TxAllowListConfig) Contract() precompile.StatefulPrecompiledContract { return TxAllowListPrecompile } // Equal returns true if [s] is a [*TxAllowListConfig] and it has been configured identical to [c]. -func (c *TxAllowListConfig) Equal(s StatefulPrecompileConfig) bool { +func (c *TxAllowListConfig) Equal(s precompile.StatefulPrecompileConfig) bool { // typecast before comparison other, ok := (s).(*TxAllowListConfig) if !ok { @@ -79,16 +75,3 @@ func (c *TxAllowListConfig) String() string { bytes, _ := json.Marshal(c) return string(bytes) } - -// GetTxAllowListStatus returns the role of [address] for the contract deployer -// allow list. -func GetTxAllowListStatus(stateDB StateDB, address common.Address) AllowListRole { - return GetAllowListStatus(stateDB, TxAllowListAddress, address) -} - -// SetTxAllowListStatus sets the permissions of [address] to [role] for the -// tx allow list. -// assumes [role] has already been verified as valid. -func SetTxAllowListStatus(stateDB StateDB, address common.Address, role AllowListRole) { - SetAllowListRole(stateDB, TxAllowListAddress, address, role) -} diff --git a/precompile/txallowlist/config_test.go b/precompile/txallowlist/config_test.go new file mode 100644 index 0000000000..651bfa9ba2 --- /dev/null +++ b/precompile/txallowlist/config_test.go @@ -0,0 +1,105 @@ +// (c) 2019-2020, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package txallowlist + +import ( + "math/big" + "testing" + + "github.com/ava-labs/subnet-evm/precompile" + "github.com/ethereum/go-ethereum/common" + "github.com/stretchr/testify/require" +) + +func TestVerifyTxAllowlistConfig(t *testing.T) { + admins := []common.Address{{1}} + enableds := []common.Address{{2}} + tests := []struct { + name string + config precompile.StatefulPrecompileConfig + expectedError string + }{ + { + name: "invalid allow list config in tx allowlist", + config: NewTxAllowListConfig(big.NewInt(3), admins, admins), + expectedError: "cannot set address", + }, + { + name: "nil member allow list config in tx allowlist", + config: NewTxAllowListConfig(big.NewInt(3), nil, nil), + expectedError: "", + }, + { + name: "empty member allow list config in tx allowlist", + config: NewTxAllowListConfig(big.NewInt(3), []common.Address{}, []common.Address{}), + expectedError: "", + }, + { + name: "valid allow list config in tx allowlist", + config: NewTxAllowListConfig(big.NewInt(3), admins, enableds), + expectedError: "", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + require := require.New(t) + + err := tt.config.Verify() + if tt.expectedError == "" { + require.NoError(err) + } else { + require.ErrorContains(err, tt.expectedError) + } + }) + } +} + +func TestEqualTxAllowListConfig(t *testing.T) { + admins := []common.Address{{1}} + enableds := []common.Address{{2}} + tests := []struct { + name string + config precompile.StatefulPrecompileConfig + other precompile.StatefulPrecompileConfig + expected bool + }{ + { + name: "non-nil config and nil other", + config: NewTxAllowListConfig(big.NewInt(3), admins, enableds), + other: nil, + expected: false, + }, + { + name: "different admin", + config: NewTxAllowListConfig(big.NewInt(3), admins, enableds), + other: NewTxAllowListConfig(big.NewInt(3), []common.Address{{3}}, enableds), + expected: false, + }, + { + name: "different enabled", + config: NewTxAllowListConfig(big.NewInt(3), admins, enableds), + other: NewTxAllowListConfig(big.NewInt(3), admins, []common.Address{{3}}), + expected: false, + }, + { + name: "different timestamp", + config: NewTxAllowListConfig(big.NewInt(3), admins, enableds), + other: NewTxAllowListConfig(big.NewInt(4), admins, enableds), + expected: false, + }, + { + name: "same config", + config: NewTxAllowListConfig(big.NewInt(3), admins, enableds), + other: NewTxAllowListConfig(big.NewInt(3), admins, enableds), + expected: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + require := require.New(t) + + require.Equal(tt.expected, tt.config.Equal(tt.other)) + }) + } +} diff --git a/precompile/txallowlist/contract.go.go b/precompile/txallowlist/contract.go.go new file mode 100644 index 0000000000..d1e9ed4b3c --- /dev/null +++ b/precompile/txallowlist/contract.go.go @@ -0,0 +1,32 @@ +// (c) 2019-2020, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package txallowlist + +import ( + "errors" + + "github.com/ava-labs/subnet-evm/precompile" + "github.com/ethereum/go-ethereum/common" +) + +var ( + _ precompile.StatefulPrecompileConfig = &TxAllowListConfig{} + // Singleton StatefulPrecompiledContract for W/R access to the contract deployer allow list. + TxAllowListPrecompile precompile.StatefulPrecompiledContract = precompile.CreateAllowListPrecompile(precompile.TxAllowListAddress) + + ErrSenderAddressNotAllowListed = errors.New("cannot issue transaction from non-allow listed address") +) + +// GetTxAllowListStatus returns the role of [address] for the contract deployer +// allow list. +func GetTxAllowListStatus(stateDB precompile.StateDB, address common.Address) precompile.AllowListRole { + return precompile.GetAllowListStatus(stateDB, precompile.TxAllowListAddress, address) +} + +// SetTxAllowListStatus sets the permissions of [address] to [role] for the +// tx allow list. +// assumes [role] has already been verified as valid. +func SetTxAllowListStatus(stateDB precompile.StateDB, address common.Address, role precompile.AllowListRole) { + precompile.SetAllowListRole(stateDB, precompile.TxAllowListAddress, address, role) +} diff --git a/precompile/utils.go b/precompile/utils.go index ee3f7accf4..dfbe4affd6 100644 --- a/precompile/utils.go +++ b/precompile/utils.go @@ -37,14 +37,14 @@ func DeductGas(suppliedGas uint64, requiredGas uint64) (uint64, error) { // packOrderedHashesWithSelector packs the function selector and ordered list of hashes into [dst] // byte slice. // assumes that [dst] has sufficient room for [functionSelector] and [hashes]. -func packOrderedHashesWithSelector(dst []byte, functionSelector []byte, hashes []common.Hash) error { +func PackOrderedHashesWithSelector(dst []byte, functionSelector []byte, hashes []common.Hash) error { copy(dst[:len(functionSelector)], functionSelector) - return packOrderedHashes(dst[len(functionSelector):], hashes) + return PackOrderedHashes(dst[len(functionSelector):], hashes) } // packOrderedHashes packs the ordered list of [hashes] into the [dst] byte buffer. // assumes that [dst] has sufficient space to pack [hashes] or else this function will panic. -func packOrderedHashes(dst []byte, hashes []common.Hash) error { +func PackOrderedHashes(dst []byte, hashes []common.Hash) error { if len(dst) != len(hashes)*common.HashLength { return fmt.Errorf("destination byte buffer has insufficient length (%d) for %d hashes", len(dst), len(hashes)) } @@ -61,10 +61,10 @@ func packOrderedHashes(dst []byte, hashes []common.Hash) error { return nil } -// returnPackedHash returns packed the byte slice with common.HashLength from [packed] +// PackedHash returns packed the byte slice with common.HashLength from [packed] // at the given [index]. // Assumes that [packed] is composed entirely of packed 32 byte segments. -func returnPackedHash(packed []byte, index int) []byte { +func PackedHash(packed []byte, index int) []byte { start := common.HashLength * index end := start + common.HashLength return packed[start:end] diff --git a/tests/e2e/utils/evm_client.go b/tests/e2e/utils/evm_client.go index 65dbe1785f..6f8c0a3950 100644 --- a/tests/e2e/utils/evm_client.go +++ b/tests/e2e/utils/evm_client.go @@ -15,7 +15,7 @@ import ( "github.com/ava-labs/subnet-evm/core/types" "github.com/ava-labs/subnet-evm/ethclient" "github.com/ava-labs/subnet-evm/params" - "github.com/ava-labs/subnet-evm/precompile" + "github.com/ava-labs/subnet-evm/precompile/txallowlist" "github.com/ethereum/go-ethereum/common" ) @@ -167,7 +167,7 @@ func (ec *EvmClient) TransferTx( if err := ec.ethClient.SendTransaction(ctx, signedTx); err != nil { log.Printf("failed to send transaction: %v (key address %s)", err, sender) - if strings.Contains(err.Error(), precompile.ErrSenderAddressNotAllowListed.Error()) { + if strings.Contains(err.Error(), txallowlist.ErrSenderAddressNotAllowListed.Error()) { return nil, err } From 6adb71bafe49d57c5d337828ff8ea71f432d2a37 Mon Sep 17 00:00:00 2001 From: Ceyhun Onur Date: Thu, 29 Dec 2022 20:34:18 +0300 Subject: [PATCH 13/23] refactor precompile template --- accounts/abi/bind/bind.go | 4 +- accounts/abi/bind/precompile_bind.go | 26 +- accounts/abi/bind/precompile_bind_test.go | 2 +- .../abi/bind/precompile_config_template.go | 157 +++++++++ ...ate.go => precompile_contract_template.go} | 127 ++----- cmd/precompilegen/main.go | 61 ++-- precompile/reward_managerx.gox/config.go | 125 +++++++ precompile/reward_managerx.gox/contract.abi | 1 + precompile/reward_managerx.gox/contract.go | 314 ++++++++++++++++++ 9 files changed, 685 insertions(+), 132 deletions(-) create mode 100644 accounts/abi/bind/precompile_config_template.go rename accounts/abi/bind/{precompile_template.go => precompile_contract_template.go} (71%) create mode 100644 precompile/reward_managerx.gox/config.go create mode 100644 precompile/reward_managerx.gox/contract.abi create mode 100644 precompile/reward_managerx.gox/contract.go diff --git a/accounts/abi/bind/bind.go b/accounts/abi/bind/bind.go index c2be8309e1..d15d452f89 100644 --- a/accounts/abi/bind/bind.go +++ b/accounts/abi/bind/bind.go @@ -51,7 +51,7 @@ const ( readAllowListFuncKey = "readAllowList" ) -type BindHook func(lang Lang, types []string, contracts map[string]*tmplContract, structs map[string]*tmplStruct) (data interface{}, templateSource string, err error) +type BindHook func(lang Lang, pkg string, types []string, contracts map[string]*tmplContract, structs map[string]*tmplStruct) (data interface{}, templateSource string, err error) // Lang is a target programming language selector to generate bindings for. type Lang int @@ -295,7 +295,7 @@ func bindHelper(types []string, abis []string, bytecodes []string, fsigs []map[s // Generate the contract template data according to hook if bindHook != nil { var err error - data, templateSource, err = bindHook(lang, types, contracts, structs) + data, templateSource, err = bindHook(lang, pkg, types, contracts, structs) if err != nil { return "", err } diff --git a/accounts/abi/bind/precompile_bind.go b/accounts/abi/bind/precompile_bind.go index 3b33478b43..d31d9d0fef 100644 --- a/accounts/abi/bind/precompile_bind.go +++ b/accounts/abi/bind/precompile_bind.go @@ -35,9 +35,23 @@ import ( "fmt" ) -func PrecompileBind(types []string, abis []string, bytecodes []string, fsigs []map[string]string, pkg string, lang Lang, libs map[string]string, aliases map[string]string, abifilename string) (string, error) { - // create hook - var createPrecompileFunc BindHook = func(lang Lang, types []string, contracts map[string]*tmplContract, structs map[string]*tmplStruct) (interface{}, string, error) { +// PrecompileBind generates a Go binding for a precompiled contract. It returns config binding and contract binding. +func PrecompileBind(types []string, abis []string, bytecodes []string, fsigs []map[string]string, pkg string, lang Lang, libs map[string]string, aliases map[string]string, abifilename string) (string, string, error) { + // create hooks + configHook := createPrecompileHook(abifilename, tmplSourcePrecompileConfigGo) + contractHook := createPrecompileHook(abifilename, tmplSourcePrecompileContractGo) + + configBind, err := bindHelper(types, abis, bytecodes, fsigs, pkg, lang, libs, aliases, configHook) + if err != nil { + return "", "", err + } + contractBind, err := bindHelper(types, abis, bytecodes, fsigs, pkg, lang, libs, aliases, contractHook) + + return configBind, contractBind, err +} + +func createPrecompileHook(abifilename string, template string) BindHook { + var bindHook BindHook = func(lang Lang, pkg string, types []string, contracts map[string]*tmplContract, structs map[string]*tmplStruct) (interface{}, string, error) { // verify first if lang != LangGo { return nil, "", errors.New("only GoLang binding for precompiled contracts is supported yet") @@ -82,11 +96,11 @@ func PrecompileBind(types []string, abis []string, bytecodes []string, fsigs []m data := &tmplPrecompileData{ Contract: precompileContract, Structs: structs, + Package: pkg, } - return data, tmplSourcePrecompileGo, nil + return data, template, nil } - - return bindHelper(types, abis, bytecodes, fsigs, pkg, lang, libs, aliases, createPrecompileFunc) + return bindHook } func allowListEnabled(funcs map[string]*tmplMethod) bool { diff --git a/accounts/abi/bind/precompile_bind_test.go b/accounts/abi/bind/precompile_bind_test.go index 8ac85fb349..23f1503142 100644 --- a/accounts/abi/bind/precompile_bind_test.go +++ b/accounts/abi/bind/precompile_bind_test.go @@ -96,7 +96,7 @@ func golangBindingsFailure(t *testing.T) { for i, tt := range bindFailedTests { t.Run(tt.name, func(t *testing.T) { // Generate the binding - _, err := PrecompileBind([]string{tt.name}, tt.abi, tt.bytecode, tt.fsigs, "bindtest", LangGo, tt.libs, tt.aliases, "") + _, _, err := PrecompileBind([]string{tt.name}, tt.abi, tt.bytecode, tt.fsigs, "bindtest", LangGo, tt.libs, tt.aliases, "") if err == nil { t.Fatalf("test %d: no error occurred but was expected", i) } diff --git a/accounts/abi/bind/precompile_config_template.go b/accounts/abi/bind/precompile_config_template.go new file mode 100644 index 0000000000..c8903131fb --- /dev/null +++ b/accounts/abi/bind/precompile_config_template.go @@ -0,0 +1,157 @@ +// (c) 2019-2022, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. +package bind + +// tmplSourcePrecompileConfigGo is the Go precompiled config source template. +const tmplSourcePrecompileConfigGo = ` +// Code generated +// This file is a generated precompile contract config with stubbed abstract functions. +// The file is generated by a template. Please inspect every code and comment in this file before use. + +// There are some must-be-done changes waiting in the file. Each area requiring you to add your code is marked with CUSTOM CODE to make them easy to find and modify. +// Additionally there are other files you need to edit to activate your precompile. +// These areas are highlighted with comments "ADD YOUR PRECOMPILE HERE". +// For testing take a look at other precompile tests in core/stateful_precompile_test.go and config_test.go in other precompile folders. + +/* General guidelines for precompile development: +1- Read the comment and set a suitable contract address in precompile/params.go. E.g: + {{.Contract.Type}}Address = common.HexToAddress("ASUITABLEHEXADDRESS") +2- Set gas costs here +3- It is recommended to only modify code in the highlighted areas marked with "CUSTOM CODE STARTS HERE". Modifying code outside of these areas should be done with caution and with a deep understanding of how these changes may impact the EVM. +Typically, custom codes are required in only those areas. +4- Add your upgradable config in params/precompile_config.go +5- Add your precompile upgrade in params/config.go +6- Add your solidity interface and test contract to contract-examples/contracts +7- Write solidity tests for your precompile in contract-examples/test +8- Create your genesis with your precompile enabled in tests/e2e/genesis/ +9- Create e2e test for your solidity test in tests/e2e/solidity/suites.go +10- Run your e2e precompile Solidity tests with 'E2E=true ./scripts/run.sh' + +*/ + +package {{.Package}} + +import ( + "encoding/json" + "math/big" + + "github.com/ava-labs/subnet-evm/precompile" + + "github.com/ethereum/go-ethereum/common" +) + +// CUSTOM CODE STARTS HERE +// Reference imports to suppress errors from unused imports. This code and any unnecessary imports can be removed. +var ( + _ = big.NewInt + _ = json.Unmarshal +) + +{{$contract := .Contract}} +var ( + _ precompile.StatefulPrecompileConfig = &{{.Contract.Type}}Config{} +) + +// {{.Contract.Type}}Config implements the StatefulPrecompileConfig +// interface while adding in the {{.Contract.Type}} specific precompile address. +type {{.Contract.Type}}Config struct { + {{- if .Contract.AllowList}} + precompile.AllowListConfig + {{- end}} + precompile.UpgradeableConfig +} + +{{$structs := .Structs}} +{{range $structs}} + // {{.Name}} is an auto generated low-level Go binding around an user-defined struct. + type {{.Name}} struct { + {{range $field := .Fields}} + {{$field.Name}} {{$field.Type}}{{end}} + } +{{- end}} + +{{- range .Contract.Funcs}} +{{ if len .Normalized.Inputs | lt 1}} +type {{capitalise .Normalized.Name}}Input struct{ +{{range .Normalized.Inputs}} {{capitalise .Name}} {{bindtype .Type $structs}}; {{end}} +} +{{- end}} +{{ if len .Normalized.Outputs | lt 1}} +type {{capitalise .Normalized.Name}}Output struct{ +{{range .Normalized.Outputs}} {{capitalise .Name}} {{bindtype .Type $structs}}; {{end}} +} +{{- end}} +{{- end}} + +// New{{.Contract.Type}}Config returns a config for a network upgrade at [blockTimestamp] that enables +// {{.Contract.Type}} {{if .Contract.AllowList}} with the given [admins] as members of the allowlist {{end}}. +func New{{.Contract.Type}}Config(blockTimestamp *big.Int{{if .Contract.AllowList}}, admins []common.Address{{end}}) *{{.Contract.Type}}Config { + return &{{.Contract.Type}}Config{ + {{if .Contract.AllowList}}AllowListConfig: precompile.AllowListConfig{AllowListAdmins: admins},{{end}} + UpgradeableConfig: precompile.UpgradeableConfig{BlockTimestamp: blockTimestamp}, + } +} + +// NewDisable{{.Contract.Type}}Config returns config for a network upgrade at [blockTimestamp] +// that disables {{.Contract.Type}}. +func NewDisable{{.Contract.Type}}Config(blockTimestamp *big.Int) *{{.Contract.Type}}Config { + return &{{.Contract.Type}}Config{ + UpgradeableConfig: precompile.UpgradeableConfig{ + BlockTimestamp: blockTimestamp, + Disable: true, + }, + } +} + +// Verify tries to verify {{.Contract.Type}}Config and returns an error accordingly. +func (c *{{.Contract.Type}}Config) Verify() error { + {{if .Contract.AllowList}} + // Verify AllowList first + if err := c.AllowListConfig.Verify(); err != nil { + return err + } + {{end}} + // CUSTOM CODE STARTS HERE + // Add your own custom verify code for {{.Contract.Type}}Config here + // and return an error accordingly + return nil +} + +// Equal returns true if [s] is a [*{{.Contract.Type}}Config] and it has been configured identical to [c]. +func (c *{{.Contract.Type}}Config) Equal(s precompile.StatefulPrecompileConfig) bool { + // typecast before comparison + other, ok := (s).(*{{.Contract.Type}}Config) + if !ok { + return false + } + // CUSTOM CODE STARTS HERE + // modify this boolean accordingly with your custom {{.Contract.Type}}Config, to check if [other] and the current [c] are equal + // if {{.Contract.Type}}Config contains only UpgradeableConfig {{if .Contract.AllowList}} and AllowListConfig {{end}} you can skip modifying it. + equals := c.UpgradeableConfig.Equal(&other.UpgradeableConfig) {{if .Contract.AllowList}} && c.AllowListConfig.Equal(&other.AllowListConfig) {{end}} + return equals +} + +// Address returns the address of the {{.Contract.Type}}. Addresses reside under the precompile/params.go +// Select a non-conflicting address and set it in the params.go. +func (c *{{.Contract.Type}}Config) Address() common.Address { + return {{.Contract.Type}}Address +} + +// Configure configures [state] with the initial configuration. +func (c *{{.Contract.Type}}Config) Configure(_ precompile.ChainConfig, state precompile.StateDB, _ precompile.BlockContext) error { + {{if .Contract.AllowList}}c.AllowListConfig.Configure(state, {{.Contract.Type}}Address){{end}} + // CUSTOM CODE STARTS HERE + return nil +} + +// Contract returns the singleton stateful precompiled contract to be used for {{.Contract.Type}}. +func (c *{{.Contract.Type}}Config) Contract() precompile.StatefulPrecompiledContract { + return {{.Contract.Type}}Precompile +} + +// String returns a string representation of the {{.Contract.Type}}Config. +func (c *{{.Contract.Type}}Config) String() string { + bytes, _ := json.Marshal(c) + return string(bytes) +} +` diff --git a/accounts/abi/bind/precompile_template.go b/accounts/abi/bind/precompile_contract_template.go similarity index 71% rename from accounts/abi/bind/precompile_template.go rename to accounts/abi/bind/precompile_contract_template.go index 6184925a81..8656a1507b 100644 --- a/accounts/abi/bind/precompile_template.go +++ b/accounts/abi/bind/precompile_contract_template.go @@ -4,6 +4,7 @@ package bind // tmplPrecompileData is the data structure required to fill the binding template. type tmplPrecompileData struct { + Package string Contract *tmplPrecompileContract // The contract to generate into this file Structs map[string]*tmplStruct // Contract struct type definitions } @@ -16,8 +17,8 @@ type tmplPrecompileContract struct { ABIFilename string // Path to the ABI file } -// tmplSourcePrecompileGo is the Go precompiled source template. -const tmplSourcePrecompileGo = ` +// tmplSourcePrecompileContractGo is the Go precompiled contract source template. +const tmplSourcePrecompileContractGo = ` // Code generated // This file is a generated precompile contract with stubbed abstract functions. // The file is generated by a template. Please inspect every code and comment in this file before use. @@ -43,7 +44,7 @@ Typically, custom codes are required in only those areas. */ -package precompile +package {{.Package}} import ( "encoding/json" @@ -53,6 +54,7 @@ import ( "strings" "github.com/ava-labs/subnet-evm/accounts/abi" + "github.com/ava-labs/subnet-evm/precompile" "github.com/ava-labs/subnet-evm/vmerrs" _ "embed" @@ -82,8 +84,6 @@ var ( {{$contract := .Contract}} // Singleton StatefulPrecompiledContract and signatures. var ( - _ StatefulPrecompileConfig = &{{.Contract.Type}}Config{} - {{- range .Contract.Funcs}} {{- if not .Original.IsConstant | and $contract.AllowList}} @@ -105,22 +105,13 @@ var ( {{- end}} {{.Contract.Type}}ABI abi.ABI // will be initialized by init function - {{.Contract.Type}}Precompile StatefulPrecompiledContract // will be initialized by init function + {{.Contract.Type}}Precompile precompile.StatefulPrecompiledContract // will be initialized by init function // CUSTOM CODE STARTS HERE // THIS SHOULD BE MOVED TO precompile/params.go with a suitable hex address. {{.Contract.Type}}Address = common.HexToAddress("ASUITABLEHEXADDRESS") ) -// {{.Contract.Type}}Config implements the StatefulPrecompileConfig -// interface while adding in the {{.Contract.Type}} specific precompile address. -type {{.Contract.Type}}Config struct { - {{- if .Contract.AllowList}} - AllowListConfig - {{- end}} - UpgradeableConfig -} - {{$structs := .Structs}} {{range $structs}} // {{.Name}} is an auto generated low-level Go binding around an user-defined struct. @@ -156,82 +147,10 @@ func init() { } } -// New{{.Contract.Type}}Config returns a config for a network upgrade at [blockTimestamp] that enables -// {{.Contract.Type}} {{if .Contract.AllowList}} with the given [admins] as members of the allowlist {{end}}. -func New{{.Contract.Type}}Config(blockTimestamp *big.Int{{if .Contract.AllowList}}, admins []common.Address{{end}}) *{{.Contract.Type}}Config { - return &{{.Contract.Type}}Config{ - {{if .Contract.AllowList}}AllowListConfig: AllowListConfig{AllowListAdmins: admins},{{end}} - UpgradeableConfig: UpgradeableConfig{BlockTimestamp: blockTimestamp}, - } -} - -// NewDisable{{.Contract.Type}}Config returns config for a network upgrade at [blockTimestamp] -// that disables {{.Contract.Type}}. -func NewDisable{{.Contract.Type}}Config(blockTimestamp *big.Int) *{{.Contract.Type}}Config { - return &{{.Contract.Type}}Config{ - UpgradeableConfig: UpgradeableConfig{ - BlockTimestamp: blockTimestamp, - Disable: true, - }, - } -} - -// Equal returns true if [s] is a [*{{.Contract.Type}}Config] and it has been configured identical to [c]. -func (c *{{.Contract.Type}}Config) Equal(s StatefulPrecompileConfig) bool { - // typecast before comparison - other, ok := (s).(*{{.Contract.Type}}Config) - if !ok { - return false - } - // CUSTOM CODE STARTS HERE - // modify this boolean accordingly with your custom {{.Contract.Type}}Config, to check if [other] and the current [c] are equal - // if {{.Contract.Type}}Config contains only UpgradeableConfig {{if .Contract.AllowList}} and AllowListConfig {{end}} you can skip modifying it. - equals := c.UpgradeableConfig.Equal(&other.UpgradeableConfig) {{if .Contract.AllowList}} && c.AllowListConfig.Equal(&other.AllowListConfig) {{end}} - return equals -} - -// String returns a string representation of the {{.Contract.Type}}Config. -func (c *{{.Contract.Type}}Config) String() string { - bytes, _ := json.Marshal(c) - return string(bytes) -} - -// Address returns the address of the {{.Contract.Type}}. Addresses reside under the precompile/params.go -// Select a non-conflicting address and set it in the params.go. -func (c *{{.Contract.Type}}Config) Address() common.Address { - return {{.Contract.Type}}Address -} - -// Configure configures [state] with the initial configuration. -func (c *{{.Contract.Type}}Config) Configure(_ ChainConfig, state StateDB, _ BlockContext) error { - {{if .Contract.AllowList}}c.AllowListConfig.Configure(state, {{.Contract.Type}}Address){{end}} - // CUSTOM CODE STARTS HERE - return nil -} - -// Contract returns the singleton stateful precompiled contract to be used for {{.Contract.Type}}. -func (c *{{.Contract.Type}}Config) Contract() StatefulPrecompiledContract { - return {{.Contract.Type}}Precompile -} - -// Verify tries to verify {{.Contract.Type}}Config and returns an error accordingly. -func (c *{{.Contract.Type}}Config) Verify() error { - {{if .Contract.AllowList}} - // Verify AllowList first - if err := c.AllowListConfig.Verify(); err != nil { - return err - } - {{end}} - // CUSTOM CODE STARTS HERE - // Add your own custom verify code for {{.Contract.Type}}Config here - // and return an error accordingly - return nil -} - {{if .Contract.AllowList}} // Get{{.Contract.Type}}AllowListStatus returns the role of [address] for the {{.Contract.Type}} list. -func Get{{.Contract.Type}}AllowListStatus(stateDB StateDB, address common.Address) AllowListRole { - return GetAllowListStatus(stateDB, {{.Contract.Type}}Address, address) +func Get{{.Contract.Type}}AllowListStatus(stateDB precompile.StateDB, address common.Address) precompile.AllowListRole { + return precompile.GetAllowListStatus(stateDB, {{.Contract.Type}}Address, address) } // Set{{.Contract.Type}}AllowListStatus sets the permissions of [address] to [role] for the @@ -240,8 +159,8 @@ func Get{{.Contract.Type}}AllowListStatus(stateDB StateDB, address common.Addres // and [address] hash. It means that any reusage of the [address] key for different value // conflicts with the same slot [role] is stored. // Precompile implementations must use a different key than [address] for their storage. -func Set{{.Contract.Type}}AllowListStatus(stateDB StateDB, address common.Address, role AllowListRole) { - SetAllowListRole(stateDB, {{.Contract.Type}}Address, address, role) +func Set{{.Contract.Type}}AllowListStatus(stateDB precompile.StateDB, address common.Address, role precompile.AllowListRole) { + precompile.SetAllowListRole(stateDB, {{.Contract.Type}}Address, address, role) } {{end}} @@ -309,8 +228,8 @@ func Pack{{$method.Normalized.Name}}Output ({{decapitalise $output.Name}} {{bind } {{end}} -func {{decapitalise .Normalized.Name}}(accessibleState PrecompileAccessibleState, caller common.Address, addr common.Address, input []byte, suppliedGas uint64, readOnly bool) (ret []byte, remainingGas uint64, err error) { - if remainingGas, err = DeductGas(suppliedGas, {{.Normalized.Name}}GasCost); err != nil { +func {{decapitalise .Normalized.Name}}(accessibleState precompile.PrecompileAccessibleState, caller common.Address, addr common.Address, input []byte, suppliedGas uint64, readOnly bool) (ret []byte, remainingGas uint64, err error) { + if remainingGas, err = precompile.DeductGas(suppliedGas, {{.Normalized.Name}}GasCost); err != nil { return nil, 0, err } @@ -338,7 +257,7 @@ func {{decapitalise .Normalized.Name}}(accessibleState PrecompileAccessibleState // You can modify/delete this code if you don't want this function to be restricted by the allow list. stateDB := accessibleState.GetStateDB() // Verify that the caller is in the allow list and therefore has the right to modify it - callerStatus := GetAllowListStatus(stateDB, {{$contract.Type}}Address, caller) + callerStatus := precompile.GetAllowListStatus(stateDB, {{$contract.Type}}Address, caller) if !callerStatus.IsEnabled() { return nil, remainingGas, fmt.Errorf("%w: %s", ErrCannot{{.Normalized.Name}}, caller) } @@ -374,8 +293,8 @@ func {{decapitalise .Normalized.Name}}(accessibleState PrecompileAccessibleState {{- with .Contract.Fallback}} // {{decapitalise $contract.Type}}Fallback executed if a function identifier does not match any of the available functions in a smart contract. // This function cannot take an input or return an output. -func {{decapitalise $contract.Type}}Fallback (accessibleState PrecompileAccessibleState, caller common.Address, addr common.Address, _ []byte, suppliedGas uint64, readOnly bool) (ret []byte, remainingGas uint64, err error) { - if remainingGas, err = DeductGas(suppliedGas, {{$contract.Type}}FallbackGasCost); err != nil { +func {{decapitalise $contract.Type}}Fallback (accessibleState precompile.PrecompileAccessibleState, caller common.Address, addr common.Address, _ []byte, suppliedGas uint64, readOnly bool) (ret []byte, remainingGas uint64, err error) { + if remainingGas, err = precompile.DeductGas(suppliedGas, {{$contract.Type}}FallbackGasCost); err != nil { return nil, 0, err } @@ -389,7 +308,7 @@ func {{decapitalise $contract.Type}}Fallback (accessibleState PrecompileAccessib // You can modify/delete this code if you don't want this function to be restricted by the allow list. stateDB := accessibleState.GetStateDB() // Verify that the caller is in the allow list and therefore has the right to modify it - callerStatus := GetAllowListStatus(stateDB, {{$contract.Type}}Address, caller) + callerStatus := precompile.GetAllowListStatus(stateDB, {{$contract.Type}}Address, caller) if !callerStatus.IsEnabled() { return nil, remainingGas, fmt.Errorf("%w: %s", Err{{$contract.Type}}CannotFallback, caller) } @@ -410,13 +329,13 @@ func {{decapitalise $contract.Type}}Fallback (accessibleState PrecompileAccessib // create{{.Contract.Type}}Precompile returns a StatefulPrecompiledContract with getters and setters for the precompile. {{if .Contract.AllowList}} // Access to the getters/setters is controlled by an allow list for [precompileAddr].{{end}} -func create{{.Contract.Type}}Precompile(precompileAddr common.Address) (StatefulPrecompiledContract, error) { - var functions []*StatefulPrecompileFunction +func create{{.Contract.Type}}Precompile(precompileAddr common.Address) (precompile.StatefulPrecompiledContract, error) { + var functions []*precompile.StatefulPrecompileFunction {{- if .Contract.AllowList}} - functions = append(functions, CreateAllowListFunctions(precompileAddr)...) + functions = append(functions, precompile.CreateAllowListFunctions(precompileAddr)...) {{- end}} - abiFunctionMap := map[string]RunStatefulPrecompileFunc{ + abiFunctionMap := map[string]precompile.RunStatefulPrecompileFunc{ {{- range .Contract.Funcs}} "{{.Original.Name}}": {{decapitalise .Normalized.Name}}, {{- end}} @@ -427,15 +346,15 @@ func create{{.Contract.Type}}Precompile(precompileAddr common.Address) (Stateful if !ok { return nil, fmt.Errorf("given method (%s) does not exist in the ABI", name) } - functions = append(functions, NewStatefulPrecompileFunction(method.ID, function)) + functions = append(functions, precompile.NewStatefulPrecompileFunction(method.ID, function)) } {{- if .Contract.Fallback}} // Construct the contract with the fallback function. - return NewStatefulPrecompileContract({{decapitalise $contract.Type}}Fallback, functions) + return precompile.NewStatefulPrecompileContract({{decapitalise $contract.Type}}Fallback, functions) {{- else}} // Construct the contract with no fallback function. - return NewStatefulPrecompileContract(nil, functions) + return precompile.NewStatefulPrecompileContract(nil, functions) {{- end}} } ` diff --git a/cmd/precompilegen/main.go b/cmd/precompilegen/main.go index 454a560bc5..0a60ed187f 100644 --- a/cmd/precompilegen/main.go +++ b/cmd/precompilegen/main.go @@ -56,15 +56,15 @@ var ( } typeFlag = &cli.StringFlag{ Name: "type", - Usage: "Struct name for the precompile (default = ABI name)", + Usage: "Struct name for the precompile (default = {ABI name})", } pkgFlag = &cli.StringFlag{ Name: "pkg", - Usage: "Package name to generate the precompile into (default = precompile)", + Usage: "Package name to generate the precompile into (default = {type})", } outFlag = &cli.StringFlag{ Name: "out", - Usage: "Output file for the generated precompile (default = STDOUT)", + Usage: "Output folder for the generated precompile files, - for STDOUT (default = ./{pkg})", } ) @@ -81,13 +81,12 @@ func init() { } func precompilegen(c *cli.Context) error { - if !c.IsSet(outFlag.Name) && !c.IsSet(typeFlag.Name) { + outFlagStr := c.String(outFlag.Name) + isOutStdout := outFlagStr == "-" + + if isOutStdout && !c.IsSet(typeFlag.Name) { utils.Fatalf("type (--type) should be set explicitly for STDOUT ") } - pkg := pkgFlag.Name - if pkg == "" { - pkg = "precompile" - } lang := bind.LangGo // If the entire solidity code was specified, build and bind based on that var ( @@ -106,6 +105,7 @@ func precompilegen(c *cli.Context) error { abi []byte err error ) + input := c.String(abiFlag.Name) if input == "-" { abi, err = io.ReadAll(os.Stdin) @@ -116,7 +116,9 @@ func precompilegen(c *cli.Context) error { utils.Fatalf("Failed to read input ABI: %v", err) } abis = append(abis, string(abi)) + bins = append(bins, "") + kind := c.String(typeFlag.Name) if kind == "" { fn := filepath.Base(input) @@ -124,30 +126,51 @@ func precompilegen(c *cli.Context) error { kind = strings.TrimSpace(kind) } types = append(types, kind) - outFlagSet := c.IsSet(outFlag.Name) - outFlag := c.String(outFlag.Name) + + pkg := c.String(pkgFlag.Name) + if pkg == "" { + pkg = strings.ToLower(kind) + } + + if outFlagStr == "" { + outFlagStr = filepath.Join("./", pkg) + } + abifilename := "" abipath := "" // we should not generate the abi file if output is set to stdout - if outFlagSet { + if !isOutStdout { // get file name from the output path - pathNoExt := strings.TrimSuffix(outFlag, filepath.Ext(outFlag)) - abipath = pathNoExt + ".abi" - abifilename = filepath.Base(abipath) + abifilename = "contract.abi" + abipath = filepath.Join(outFlagStr, abifilename) } // Generate the contract precompile - code, err := bind.PrecompileBind(types, abis, bins, sigs, pkg, lang, libs, aliases, abifilename) + configCode, contractCode, err := bind.PrecompileBind(types, abis, bins, sigs, pkg, lang, libs, aliases, abifilename) if err != nil { utils.Fatalf("Failed to generate ABI precompile: %v", err) } // Either flush it out to a file or display on the standard output - if !outFlagSet { - fmt.Printf("%s\n", code) + if isOutStdout { + fmt.Print("-----Config Code-----\n") + fmt.Printf("%s\n", configCode) + fmt.Print("-----Contract Code-----\n") + fmt.Printf("%s\n", contractCode) return nil } - if err := os.WriteFile(outFlag, []byte(code), 0o600); err != nil { + if _, err := os.Stat(outFlagStr); os.IsNotExist(err) { + os.MkdirAll(outFlagStr, 0700) // Create your file + } + configCodeOut := filepath.Join(outFlagStr, "config.go") + + if err := os.WriteFile(configCodeOut, []byte(configCode), 0o600); err != nil { + utils.Fatalf("Failed to write generated precompile: %v", err) + } + + contractCodeOut := filepath.Join(outFlagStr, "contract.go") + + if err := os.WriteFile(contractCodeOut, []byte(contractCode), 0o600); err != nil { utils.Fatalf("Failed to write generated precompile: %v", err) } @@ -155,7 +178,7 @@ func precompilegen(c *cli.Context) error { utils.Fatalf("Failed to write ABI: %v", err) } - fmt.Println("Precompile Generation was a success!") + fmt.Println("Precompile files generated successfully at: ", outFlagStr) return nil } diff --git a/precompile/reward_managerx.gox/config.go b/precompile/reward_managerx.gox/config.go new file mode 100644 index 0000000000..85ed1f0366 --- /dev/null +++ b/precompile/reward_managerx.gox/config.go @@ -0,0 +1,125 @@ +// Code generated +// This file is a generated precompile contract config with stubbed abstract functions. +// The file is generated by a template. Please inspect every code and comment in this file before use. + +// There are some must-be-done changes waiting in the file. Each area requiring you to add your code is marked with CUSTOM CODE to make them easy to find and modify. +// Additionally there are other files you need to edit to activate your precompile. +// These areas are highlighted with comments "ADD YOUR PRECOMPILE HERE". +// For testing take a look at other precompile tests in core/stateful_precompile_test.go and config_test.go in other precompile folders. + +/* General guidelines for precompile development: +1- Read the comment and set a suitable contract address in precompile/params.go. E.g: + RewardManagerAddress = common.HexToAddress("ASUITABLEHEXADDRESS") +2- Set gas costs here +3- It is recommended to only modify code in the highlighted areas marked with "CUSTOM CODE STARTS HERE". Modifying code outside of these areas should be done with caution and with a deep understanding of how these changes may impact the EVM. +Typically, custom codes are required in only those areas. +4- Add your upgradable config in params/precompile_config.go +5- Add your precompile upgrade in params/config.go +6- Add your solidity interface and test contract to contract-examples/contracts +7- Write solidity tests for your precompile in contract-examples/test +8- Create your genesis with your precompile enabled in tests/e2e/genesis/ +9- Create e2e test for your solidity test in tests/e2e/solidity/suites.go +10- Run your e2e precompile Solidity tests with 'E2E=true ./scripts/run.sh' + +*/ + +package rewardmanager + +import ( + "encoding/json" + "math/big" + + "github.com/ava-labs/subnet-evm/precompile" + + "github.com/ethereum/go-ethereum/common" +) + +// CUSTOM CODE STARTS HERE +// Reference imports to suppress errors from unused imports. This code and any unnecessary imports can be removed. +var ( + _ = big.NewInt + _ = json.Unmarshal +) + +var ( + _ precompile.StatefulPrecompileConfig = &RewardManagerConfig{} +) + +// RewardManagerConfig implements the StatefulPrecompileConfig +// interface while adding in the RewardManager specific precompile address. +type RewardManagerConfig struct { + precompile.AllowListConfig + precompile.UpgradeableConfig +} + +// NewRewardManagerConfig returns a config for a network upgrade at [blockTimestamp] that enables +// RewardManager with the given [admins] as members of the allowlist . +func NewRewardManagerConfig(blockTimestamp *big.Int, admins []common.Address) *RewardManagerConfig { + return &RewardManagerConfig{ + AllowListConfig: precompile.AllowListConfig{AllowListAdmins: admins}, + UpgradeableConfig: precompile.UpgradeableConfig{BlockTimestamp: blockTimestamp}, + } +} + +// NewDisableRewardManagerConfig returns config for a network upgrade at [blockTimestamp] +// that disables RewardManager. +func NewDisableRewardManagerConfig(blockTimestamp *big.Int) *RewardManagerConfig { + return &RewardManagerConfig{ + UpgradeableConfig: precompile.UpgradeableConfig{ + BlockTimestamp: blockTimestamp, + Disable: true, + }, + } +} + +// Verify tries to verify RewardManagerConfig and returns an error accordingly. +func (c *RewardManagerConfig) Verify() error { + + // Verify AllowList first + if err := c.AllowListConfig.Verify(); err != nil { + return err + } + + // CUSTOM CODE STARTS HERE + // Add your own custom verify code for RewardManagerConfig here + // and return an error accordingly + return nil +} + +// Equal returns true if [s] is a [*RewardManagerConfig] and it has been configured identical to [c]. +func (c *RewardManagerConfig) Equal(s precompile.StatefulPrecompileConfig) bool { + // typecast before comparison + other, ok := (s).(*RewardManagerConfig) + if !ok { + return false + } + // CUSTOM CODE STARTS HERE + // modify this boolean accordingly with your custom RewardManagerConfig, to check if [other] and the current [c] are equal + // if RewardManagerConfig contains only UpgradeableConfig and AllowListConfig you can skip modifying it. + equals := c.UpgradeableConfig.Equal(&other.UpgradeableConfig) && c.AllowListConfig.Equal(&other.AllowListConfig) + return equals +} + +// Address returns the address of the RewardManager. Addresses reside under the precompile/params.go +// Select a non-conflicting address and set it in the params.go. +func (c *RewardManagerConfig) Address() common.Address { + return RewardManagerAddress +} + +// Configure configures [state] with the initial configuration. +func (c *RewardManagerConfig) Configure(_ precompile.ChainConfig, state precompile.StateDB, _ precompile.BlockContext) error { + c.AllowListConfig.Configure(state, RewardManagerAddress) + // CUSTOM CODE STARTS HERE + return nil +} + +// Contract returns the singleton stateful precompiled contract to be used for RewardManager. +func (c *RewardManagerConfig) Contract() precompile.StatefulPrecompiledContract { + return RewardManagerPrecompile +} + +// String returns a string representation of the RewardManagerConfig. +func (c *RewardManagerConfig) String() string { + bytes, _ := json.Marshal(c) + return string(bytes) +} diff --git a/precompile/reward_managerx.gox/contract.abi b/precompile/reward_managerx.gox/contract.abi new file mode 100644 index 0000000000..d21d5bdc6b --- /dev/null +++ b/precompile/reward_managerx.gox/contract.abi @@ -0,0 +1 @@ +[{"inputs":[],"name":"allowFeeRecipients","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"areFeeRecipientsAllowed","outputs":[{"internalType":"bool","name":"isAllowed","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"currentRewardAddress","outputs":[{"internalType":"address","name":"rewardAddress","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"disableRewards","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"readAllowList","outputs":[{"internalType":"uint256","name":"role","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"setAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"setEnabled","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"setNone","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"setRewardAddress","outputs":[],"stateMutability":"nonpayable","type":"function"}] \ No newline at end of file diff --git a/precompile/reward_managerx.gox/contract.go b/precompile/reward_managerx.gox/contract.go new file mode 100644 index 0000000000..5d72ef402d --- /dev/null +++ b/precompile/reward_managerx.gox/contract.go @@ -0,0 +1,314 @@ +// Code generated +// This file is a generated precompile contract with stubbed abstract functions. +// The file is generated by a template. Please inspect every code and comment in this file before use. + +// There are some must-be-done changes waiting in the file. Each area requiring you to add your code is marked with CUSTOM CODE to make them easy to find and modify. +// Additionally there are other files you need to edit to activate your precompile. +// These areas are highlighted with comments "ADD YOUR PRECOMPILE HERE". +// For testing take a look at other precompile tests in core/stateful_precompile_test.go + +/* General guidelines for precompile development: +1- Read the comment and set a suitable contract address in precompile/params.go. E.g: + RewardManagerAddress = common.HexToAddress("ASUITABLEHEXADDRESS") +2- Set gas costs here +3- It is recommended to only modify code in the highlighted areas marked with "CUSTOM CODE STARTS HERE". Modifying code outside of these areas should be done with caution and with a deep understanding of how these changes may impact the EVM. +Typically, custom codes are required in only those areas. +4- Add your upgradable config in params/precompile_config.go +5- Add your precompile upgrade in params/config.go +6- Add your solidity interface and test contract to contract-examples/contracts +7- Write solidity tests for your precompile in contract-examples/test +8- Create your genesis with your precompile enabled in tests/e2e/genesis/ +9- Create e2e test for your solidity test in tests/e2e/solidity/suites.go +10- Run your e2e precompile Solidity tests with 'E2E=true ./scripts/run.sh' + +*/ + +package rewardmanager + +import ( + "encoding/json" + "errors" + "fmt" + "math/big" + "strings" + + "github.com/ava-labs/subnet-evm/accounts/abi" + "github.com/ava-labs/subnet-evm/precompile" + "github.com/ava-labs/subnet-evm/vmerrs" + + _ "embed" + + "github.com/ethereum/go-ethereum/common" +) + +const ( + AllowFeeRecipientsGasCost uint64 = 0 // SET A GAS COST HERE + AreFeeRecipientsAllowedGasCost uint64 = 0 // SET A GAS COST HERE + CurrentRewardAddressGasCost uint64 = 0 // SET A GAS COST HERE + DisableRewardsGasCost uint64 = 0 // SET A GAS COST HERE + SetRewardAddressGasCost uint64 = 0 // SET A GAS COST HERE +) + +// CUSTOM CODE STARTS HERE +// Reference imports to suppress errors from unused imports. This code and any unnecessary imports can be removed. +var ( + _ = errors.New + _ = big.NewInt + _ = strings.NewReader + _ = fmt.Printf + _ = json.Unmarshal +) + +// Singleton StatefulPrecompiledContract and signatures. +var ( + ErrCannotAllowFeeRecipients = errors.New("non-enabled cannot call allowFeeRecipients") + + ErrCannotDisableRewards = errors.New("non-enabled cannot call disableRewards") + + ErrCannotSetRewardAddress = errors.New("non-enabled cannot call setRewardAddress") + + // RewardManagerRawABI contains the raw ABI of RewardManager contract. + //go:embed contract.abi + RewardManagerRawABI string + RewardManagerABI abi.ABI // will be initialized by init function + + RewardManagerPrecompile precompile.StatefulPrecompiledContract // will be initialized by init function + + // CUSTOM CODE STARTS HERE + // THIS SHOULD BE MOVED TO precompile/params.go with a suitable hex address. + RewardManagerAddress = common.HexToAddress("ASUITABLEHEXADDRESS") +) + +func init() { + parsed, err := abi.JSON(strings.NewReader(RewardManagerRawABI)) + if err != nil { + panic(err) + } + RewardManagerABI = parsed + + RewardManagerPrecompile, err = createRewardManagerPrecompile(RewardManagerAddress) + if err != nil { + panic(err) + } +} + +// GetRewardManagerAllowListStatus returns the role of [address] for the RewardManager list. +func GetRewardManagerAllowListStatus(stateDB precompile.StateDB, address common.Address) precompile.AllowListRole { + return precompile.GetAllowListStatus(stateDB, RewardManagerAddress, address) +} + +// SetRewardManagerAllowListStatus sets the permissions of [address] to [role] for the +// RewardManager list. Assumes [role] has already been verified as valid. +// This stores the [role] in the contract storage with address [RewardManagerAddress] +// and [address] hash. It means that any reusage of the [address] key for different value +// conflicts with the same slot [role] is stored. +// Precompile implementations must use a different key than [address] for their storage. +func SetRewardManagerAllowListStatus(stateDB precompile.StateDB, address common.Address, role precompile.AllowListRole) { + precompile.SetAllowListRole(stateDB, RewardManagerAddress, address, role) +} + +// PackAllowFeeRecipients packs the include selector (first 4 func signature bytes). +// This function is mostly used for tests. +func PackAllowFeeRecipients() ([]byte, error) { + return RewardManagerABI.Pack("allowFeeRecipients") +} + +func allowFeeRecipients(accessibleState precompile.PrecompileAccessibleState, caller common.Address, addr common.Address, input []byte, suppliedGas uint64, readOnly bool) (ret []byte, remainingGas uint64, err error) { + if remainingGas, err = precompile.DeductGas(suppliedGas, AllowFeeRecipientsGasCost); err != nil { + return nil, 0, err + } + if readOnly { + return nil, remainingGas, vmerrs.ErrWriteProtection + } + // no input provided for this function + + // Allow list is enabled and AllowFeeRecipients is a state-changer function. + // This part of the code restricts the function to be called only by enabled/admin addresses in the allow list. + // You can modify/delete this code if you don't want this function to be restricted by the allow list. + stateDB := accessibleState.GetStateDB() + // Verify that the caller is in the allow list and therefore has the right to modify it + callerStatus := precompile.GetAllowListStatus(stateDB, RewardManagerAddress, caller) + if !callerStatus.IsEnabled() { + return nil, remainingGas, fmt.Errorf("%w: %s", ErrCannotAllowFeeRecipients, caller) + } + // allow list code ends here. + + // CUSTOM CODE STARTS HERE + // this function does not return an output, leave this one as is + packedOutput := []byte{} + + // Return the packed output and the remaining gas + return packedOutput, remainingGas, nil +} + +// PackAreFeeRecipientsAllowed packs the include selector (first 4 func signature bytes). +// This function is mostly used for tests. +func PackAreFeeRecipientsAllowed() ([]byte, error) { + return RewardManagerABI.Pack("areFeeRecipientsAllowed") +} + +// PackAreFeeRecipientsAllowedOutput attempts to pack given isAllowed of type bool +// to conform the ABI outputs. +func PackAreFeeRecipientsAllowedOutput(isAllowed bool) ([]byte, error) { + return RewardManagerABI.PackOutput("areFeeRecipientsAllowed", isAllowed) +} + +func areFeeRecipientsAllowed(accessibleState precompile.PrecompileAccessibleState, caller common.Address, addr common.Address, input []byte, suppliedGas uint64, readOnly bool) (ret []byte, remainingGas uint64, err error) { + if remainingGas, err = precompile.DeductGas(suppliedGas, AreFeeRecipientsAllowedGasCost); err != nil { + return nil, 0, err + } + // no input provided for this function + + // CUSTOM CODE STARTS HERE + + var output bool // CUSTOM CODE FOR AN OUTPUT + packedOutput, err := PackAreFeeRecipientsAllowedOutput(output) + if err != nil { + return nil, remainingGas, err + } + + // Return the packed output and the remaining gas + return packedOutput, remainingGas, nil +} + +// PackCurrentRewardAddress packs the include selector (first 4 func signature bytes). +// This function is mostly used for tests. +func PackCurrentRewardAddress() ([]byte, error) { + return RewardManagerABI.Pack("currentRewardAddress") +} + +// PackCurrentRewardAddressOutput attempts to pack given rewardAddress of type common.Address +// to conform the ABI outputs. +func PackCurrentRewardAddressOutput(rewardAddress common.Address) ([]byte, error) { + return RewardManagerABI.PackOutput("currentRewardAddress", rewardAddress) +} + +func currentRewardAddress(accessibleState precompile.PrecompileAccessibleState, caller common.Address, addr common.Address, input []byte, suppliedGas uint64, readOnly bool) (ret []byte, remainingGas uint64, err error) { + if remainingGas, err = precompile.DeductGas(suppliedGas, CurrentRewardAddressGasCost); err != nil { + return nil, 0, err + } + // no input provided for this function + + // CUSTOM CODE STARTS HERE + + var output common.Address // CUSTOM CODE FOR AN OUTPUT + packedOutput, err := PackCurrentRewardAddressOutput(output) + if err != nil { + return nil, remainingGas, err + } + + // Return the packed output and the remaining gas + return packedOutput, remainingGas, nil +} + +// PackDisableRewards packs the include selector (first 4 func signature bytes). +// This function is mostly used for tests. +func PackDisableRewards() ([]byte, error) { + return RewardManagerABI.Pack("disableRewards") +} + +func disableRewards(accessibleState precompile.PrecompileAccessibleState, caller common.Address, addr common.Address, input []byte, suppliedGas uint64, readOnly bool) (ret []byte, remainingGas uint64, err error) { + if remainingGas, err = precompile.DeductGas(suppliedGas, DisableRewardsGasCost); err != nil { + return nil, 0, err + } + if readOnly { + return nil, remainingGas, vmerrs.ErrWriteProtection + } + // no input provided for this function + + // Allow list is enabled and DisableRewards is a state-changer function. + // This part of the code restricts the function to be called only by enabled/admin addresses in the allow list. + // You can modify/delete this code if you don't want this function to be restricted by the allow list. + stateDB := accessibleState.GetStateDB() + // Verify that the caller is in the allow list and therefore has the right to modify it + callerStatus := precompile.GetAllowListStatus(stateDB, RewardManagerAddress, caller) + if !callerStatus.IsEnabled() { + return nil, remainingGas, fmt.Errorf("%w: %s", ErrCannotDisableRewards, caller) + } + // allow list code ends here. + + // CUSTOM CODE STARTS HERE + // this function does not return an output, leave this one as is + packedOutput := []byte{} + + // Return the packed output and the remaining gas + return packedOutput, remainingGas, nil +} + +// UnpackSetRewardAddressInput attempts to unpack [input] into the common.Address type argument +// assumes that [input] does not include selector (omits first 4 func signature bytes) +func UnpackSetRewardAddressInput(input []byte) (common.Address, error) { + res, err := RewardManagerABI.UnpackInput("setRewardAddress", input) + if err != nil { + return common.Address{}, err + } + unpacked := *abi.ConvertType(res[0], new(common.Address)).(*common.Address) + return unpacked, nil +} + +// PackSetRewardAddress packs [addr] of type common.Address into the appropriate arguments for setRewardAddress. +// the packed bytes include selector (first 4 func signature bytes). +// This function is mostly used for tests. +func PackSetRewardAddress(addr common.Address) ([]byte, error) { + return RewardManagerABI.Pack("setRewardAddress", addr) +} + +func setRewardAddress(accessibleState precompile.PrecompileAccessibleState, caller common.Address, addr common.Address, input []byte, suppliedGas uint64, readOnly bool) (ret []byte, remainingGas uint64, err error) { + if remainingGas, err = precompile.DeductGas(suppliedGas, SetRewardAddressGasCost); err != nil { + return nil, 0, err + } + if readOnly { + return nil, remainingGas, vmerrs.ErrWriteProtection + } + // attempts to unpack [input] into the arguments to the SetRewardAddressInput. + // Assumes that [input] does not include selector + // You can use unpacked [inputStruct] variable in your code + inputStruct, err := UnpackSetRewardAddressInput(input) + if err != nil { + return nil, remainingGas, err + } + + // Allow list is enabled and SetRewardAddress is a state-changer function. + // This part of the code restricts the function to be called only by enabled/admin addresses in the allow list. + // You can modify/delete this code if you don't want this function to be restricted by the allow list. + stateDB := accessibleState.GetStateDB() + // Verify that the caller is in the allow list and therefore has the right to modify it + callerStatus := precompile.GetAllowListStatus(stateDB, RewardManagerAddress, caller) + if !callerStatus.IsEnabled() { + return nil, remainingGas, fmt.Errorf("%w: %s", ErrCannotSetRewardAddress, caller) + } + // allow list code ends here. + + // CUSTOM CODE STARTS HERE + _ = inputStruct // CUSTOM CODE OPERATES ON INPUT + // this function does not return an output, leave this one as is + packedOutput := []byte{} + + // Return the packed output and the remaining gas + return packedOutput, remainingGas, nil +} + +// createRewardManagerPrecompile returns a StatefulPrecompiledContract with getters and setters for the precompile. +// Access to the getters/setters is controlled by an allow list for [precompileAddr]. +func createRewardManagerPrecompile(precompileAddr common.Address) (precompile.StatefulPrecompiledContract, error) { + var functions []*precompile.StatefulPrecompileFunction + functions = append(functions, precompile.CreateAllowListFunctions(precompileAddr)...) + + abiFunctionMap := map[string]precompile.RunStatefulPrecompileFunc{ + "allowFeeRecipients": allowFeeRecipients, + "areFeeRecipientsAllowed": areFeeRecipientsAllowed, + "currentRewardAddress": currentRewardAddress, + "disableRewards": disableRewards, + "setRewardAddress": setRewardAddress, + } + + for name, function := range abiFunctionMap { + method, ok := RewardManagerABI.Methods[name] + if !ok { + return nil, fmt.Errorf("given method (%s) does not exist in the ABI", name) + } + functions = append(functions, precompile.NewStatefulPrecompileFunction(method.ID, function)) + } + // Construct the contract with no fallback function. + return precompile.NewStatefulPrecompileContract(nil, functions) +} From 00dc16d5a85f749ea91a41b49179a090603f1a46 Mon Sep 17 00:00:00 2001 From: Ceyhun Onur Date: Thu, 29 Dec 2022 20:57:48 +0300 Subject: [PATCH 14/23] remove test file --- abis/IAllowList.abi | 1 + .../contract.abi => abis/IRewardManager.abi | 0 precompile/reward_managerx.gox/config.go | 125 ------- precompile/reward_managerx.gox/contract.go | 314 ------------------ 4 files changed, 1 insertion(+), 439 deletions(-) create mode 100644 abis/IAllowList.abi rename precompile/reward_managerx.gox/contract.abi => abis/IRewardManager.abi (100%) delete mode 100644 precompile/reward_managerx.gox/config.go delete mode 100644 precompile/reward_managerx.gox/contract.go diff --git a/abis/IAllowList.abi b/abis/IAllowList.abi new file mode 100644 index 0000000000..ea89cd6408 --- /dev/null +++ b/abis/IAllowList.abi @@ -0,0 +1 @@ +[{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"readAllowList","outputs":[{"internalType":"uint256","name":"role","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"setAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"setEnabled","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"setNone","outputs":[],"stateMutability":"nonpayable","type":"function"}] \ No newline at end of file diff --git a/precompile/reward_managerx.gox/contract.abi b/abis/IRewardManager.abi similarity index 100% rename from precompile/reward_managerx.gox/contract.abi rename to abis/IRewardManager.abi diff --git a/precompile/reward_managerx.gox/config.go b/precompile/reward_managerx.gox/config.go deleted file mode 100644 index 85ed1f0366..0000000000 --- a/precompile/reward_managerx.gox/config.go +++ /dev/null @@ -1,125 +0,0 @@ -// Code generated -// This file is a generated precompile contract config with stubbed abstract functions. -// The file is generated by a template. Please inspect every code and comment in this file before use. - -// There are some must-be-done changes waiting in the file. Each area requiring you to add your code is marked with CUSTOM CODE to make them easy to find and modify. -// Additionally there are other files you need to edit to activate your precompile. -// These areas are highlighted with comments "ADD YOUR PRECOMPILE HERE". -// For testing take a look at other precompile tests in core/stateful_precompile_test.go and config_test.go in other precompile folders. - -/* General guidelines for precompile development: -1- Read the comment and set a suitable contract address in precompile/params.go. E.g: - RewardManagerAddress = common.HexToAddress("ASUITABLEHEXADDRESS") -2- Set gas costs here -3- It is recommended to only modify code in the highlighted areas marked with "CUSTOM CODE STARTS HERE". Modifying code outside of these areas should be done with caution and with a deep understanding of how these changes may impact the EVM. -Typically, custom codes are required in only those areas. -4- Add your upgradable config in params/precompile_config.go -5- Add your precompile upgrade in params/config.go -6- Add your solidity interface and test contract to contract-examples/contracts -7- Write solidity tests for your precompile in contract-examples/test -8- Create your genesis with your precompile enabled in tests/e2e/genesis/ -9- Create e2e test for your solidity test in tests/e2e/solidity/suites.go -10- Run your e2e precompile Solidity tests with 'E2E=true ./scripts/run.sh' - -*/ - -package rewardmanager - -import ( - "encoding/json" - "math/big" - - "github.com/ava-labs/subnet-evm/precompile" - - "github.com/ethereum/go-ethereum/common" -) - -// CUSTOM CODE STARTS HERE -// Reference imports to suppress errors from unused imports. This code and any unnecessary imports can be removed. -var ( - _ = big.NewInt - _ = json.Unmarshal -) - -var ( - _ precompile.StatefulPrecompileConfig = &RewardManagerConfig{} -) - -// RewardManagerConfig implements the StatefulPrecompileConfig -// interface while adding in the RewardManager specific precompile address. -type RewardManagerConfig struct { - precompile.AllowListConfig - precompile.UpgradeableConfig -} - -// NewRewardManagerConfig returns a config for a network upgrade at [blockTimestamp] that enables -// RewardManager with the given [admins] as members of the allowlist . -func NewRewardManagerConfig(blockTimestamp *big.Int, admins []common.Address) *RewardManagerConfig { - return &RewardManagerConfig{ - AllowListConfig: precompile.AllowListConfig{AllowListAdmins: admins}, - UpgradeableConfig: precompile.UpgradeableConfig{BlockTimestamp: blockTimestamp}, - } -} - -// NewDisableRewardManagerConfig returns config for a network upgrade at [blockTimestamp] -// that disables RewardManager. -func NewDisableRewardManagerConfig(blockTimestamp *big.Int) *RewardManagerConfig { - return &RewardManagerConfig{ - UpgradeableConfig: precompile.UpgradeableConfig{ - BlockTimestamp: blockTimestamp, - Disable: true, - }, - } -} - -// Verify tries to verify RewardManagerConfig and returns an error accordingly. -func (c *RewardManagerConfig) Verify() error { - - // Verify AllowList first - if err := c.AllowListConfig.Verify(); err != nil { - return err - } - - // CUSTOM CODE STARTS HERE - // Add your own custom verify code for RewardManagerConfig here - // and return an error accordingly - return nil -} - -// Equal returns true if [s] is a [*RewardManagerConfig] and it has been configured identical to [c]. -func (c *RewardManagerConfig) Equal(s precompile.StatefulPrecompileConfig) bool { - // typecast before comparison - other, ok := (s).(*RewardManagerConfig) - if !ok { - return false - } - // CUSTOM CODE STARTS HERE - // modify this boolean accordingly with your custom RewardManagerConfig, to check if [other] and the current [c] are equal - // if RewardManagerConfig contains only UpgradeableConfig and AllowListConfig you can skip modifying it. - equals := c.UpgradeableConfig.Equal(&other.UpgradeableConfig) && c.AllowListConfig.Equal(&other.AllowListConfig) - return equals -} - -// Address returns the address of the RewardManager. Addresses reside under the precompile/params.go -// Select a non-conflicting address and set it in the params.go. -func (c *RewardManagerConfig) Address() common.Address { - return RewardManagerAddress -} - -// Configure configures [state] with the initial configuration. -func (c *RewardManagerConfig) Configure(_ precompile.ChainConfig, state precompile.StateDB, _ precompile.BlockContext) error { - c.AllowListConfig.Configure(state, RewardManagerAddress) - // CUSTOM CODE STARTS HERE - return nil -} - -// Contract returns the singleton stateful precompiled contract to be used for RewardManager. -func (c *RewardManagerConfig) Contract() precompile.StatefulPrecompiledContract { - return RewardManagerPrecompile -} - -// String returns a string representation of the RewardManagerConfig. -func (c *RewardManagerConfig) String() string { - bytes, _ := json.Marshal(c) - return string(bytes) -} diff --git a/precompile/reward_managerx.gox/contract.go b/precompile/reward_managerx.gox/contract.go deleted file mode 100644 index 5d72ef402d..0000000000 --- a/precompile/reward_managerx.gox/contract.go +++ /dev/null @@ -1,314 +0,0 @@ -// Code generated -// This file is a generated precompile contract with stubbed abstract functions. -// The file is generated by a template. Please inspect every code and comment in this file before use. - -// There are some must-be-done changes waiting in the file. Each area requiring you to add your code is marked with CUSTOM CODE to make them easy to find and modify. -// Additionally there are other files you need to edit to activate your precompile. -// These areas are highlighted with comments "ADD YOUR PRECOMPILE HERE". -// For testing take a look at other precompile tests in core/stateful_precompile_test.go - -/* General guidelines for precompile development: -1- Read the comment and set a suitable contract address in precompile/params.go. E.g: - RewardManagerAddress = common.HexToAddress("ASUITABLEHEXADDRESS") -2- Set gas costs here -3- It is recommended to only modify code in the highlighted areas marked with "CUSTOM CODE STARTS HERE". Modifying code outside of these areas should be done with caution and with a deep understanding of how these changes may impact the EVM. -Typically, custom codes are required in only those areas. -4- Add your upgradable config in params/precompile_config.go -5- Add your precompile upgrade in params/config.go -6- Add your solidity interface and test contract to contract-examples/contracts -7- Write solidity tests for your precompile in contract-examples/test -8- Create your genesis with your precompile enabled in tests/e2e/genesis/ -9- Create e2e test for your solidity test in tests/e2e/solidity/suites.go -10- Run your e2e precompile Solidity tests with 'E2E=true ./scripts/run.sh' - -*/ - -package rewardmanager - -import ( - "encoding/json" - "errors" - "fmt" - "math/big" - "strings" - - "github.com/ava-labs/subnet-evm/accounts/abi" - "github.com/ava-labs/subnet-evm/precompile" - "github.com/ava-labs/subnet-evm/vmerrs" - - _ "embed" - - "github.com/ethereum/go-ethereum/common" -) - -const ( - AllowFeeRecipientsGasCost uint64 = 0 // SET A GAS COST HERE - AreFeeRecipientsAllowedGasCost uint64 = 0 // SET A GAS COST HERE - CurrentRewardAddressGasCost uint64 = 0 // SET A GAS COST HERE - DisableRewardsGasCost uint64 = 0 // SET A GAS COST HERE - SetRewardAddressGasCost uint64 = 0 // SET A GAS COST HERE -) - -// CUSTOM CODE STARTS HERE -// Reference imports to suppress errors from unused imports. This code and any unnecessary imports can be removed. -var ( - _ = errors.New - _ = big.NewInt - _ = strings.NewReader - _ = fmt.Printf - _ = json.Unmarshal -) - -// Singleton StatefulPrecompiledContract and signatures. -var ( - ErrCannotAllowFeeRecipients = errors.New("non-enabled cannot call allowFeeRecipients") - - ErrCannotDisableRewards = errors.New("non-enabled cannot call disableRewards") - - ErrCannotSetRewardAddress = errors.New("non-enabled cannot call setRewardAddress") - - // RewardManagerRawABI contains the raw ABI of RewardManager contract. - //go:embed contract.abi - RewardManagerRawABI string - RewardManagerABI abi.ABI // will be initialized by init function - - RewardManagerPrecompile precompile.StatefulPrecompiledContract // will be initialized by init function - - // CUSTOM CODE STARTS HERE - // THIS SHOULD BE MOVED TO precompile/params.go with a suitable hex address. - RewardManagerAddress = common.HexToAddress("ASUITABLEHEXADDRESS") -) - -func init() { - parsed, err := abi.JSON(strings.NewReader(RewardManagerRawABI)) - if err != nil { - panic(err) - } - RewardManagerABI = parsed - - RewardManagerPrecompile, err = createRewardManagerPrecompile(RewardManagerAddress) - if err != nil { - panic(err) - } -} - -// GetRewardManagerAllowListStatus returns the role of [address] for the RewardManager list. -func GetRewardManagerAllowListStatus(stateDB precompile.StateDB, address common.Address) precompile.AllowListRole { - return precompile.GetAllowListStatus(stateDB, RewardManagerAddress, address) -} - -// SetRewardManagerAllowListStatus sets the permissions of [address] to [role] for the -// RewardManager list. Assumes [role] has already been verified as valid. -// This stores the [role] in the contract storage with address [RewardManagerAddress] -// and [address] hash. It means that any reusage of the [address] key for different value -// conflicts with the same slot [role] is stored. -// Precompile implementations must use a different key than [address] for their storage. -func SetRewardManagerAllowListStatus(stateDB precompile.StateDB, address common.Address, role precompile.AllowListRole) { - precompile.SetAllowListRole(stateDB, RewardManagerAddress, address, role) -} - -// PackAllowFeeRecipients packs the include selector (first 4 func signature bytes). -// This function is mostly used for tests. -func PackAllowFeeRecipients() ([]byte, error) { - return RewardManagerABI.Pack("allowFeeRecipients") -} - -func allowFeeRecipients(accessibleState precompile.PrecompileAccessibleState, caller common.Address, addr common.Address, input []byte, suppliedGas uint64, readOnly bool) (ret []byte, remainingGas uint64, err error) { - if remainingGas, err = precompile.DeductGas(suppliedGas, AllowFeeRecipientsGasCost); err != nil { - return nil, 0, err - } - if readOnly { - return nil, remainingGas, vmerrs.ErrWriteProtection - } - // no input provided for this function - - // Allow list is enabled and AllowFeeRecipients is a state-changer function. - // This part of the code restricts the function to be called only by enabled/admin addresses in the allow list. - // You can modify/delete this code if you don't want this function to be restricted by the allow list. - stateDB := accessibleState.GetStateDB() - // Verify that the caller is in the allow list and therefore has the right to modify it - callerStatus := precompile.GetAllowListStatus(stateDB, RewardManagerAddress, caller) - if !callerStatus.IsEnabled() { - return nil, remainingGas, fmt.Errorf("%w: %s", ErrCannotAllowFeeRecipients, caller) - } - // allow list code ends here. - - // CUSTOM CODE STARTS HERE - // this function does not return an output, leave this one as is - packedOutput := []byte{} - - // Return the packed output and the remaining gas - return packedOutput, remainingGas, nil -} - -// PackAreFeeRecipientsAllowed packs the include selector (first 4 func signature bytes). -// This function is mostly used for tests. -func PackAreFeeRecipientsAllowed() ([]byte, error) { - return RewardManagerABI.Pack("areFeeRecipientsAllowed") -} - -// PackAreFeeRecipientsAllowedOutput attempts to pack given isAllowed of type bool -// to conform the ABI outputs. -func PackAreFeeRecipientsAllowedOutput(isAllowed bool) ([]byte, error) { - return RewardManagerABI.PackOutput("areFeeRecipientsAllowed", isAllowed) -} - -func areFeeRecipientsAllowed(accessibleState precompile.PrecompileAccessibleState, caller common.Address, addr common.Address, input []byte, suppliedGas uint64, readOnly bool) (ret []byte, remainingGas uint64, err error) { - if remainingGas, err = precompile.DeductGas(suppliedGas, AreFeeRecipientsAllowedGasCost); err != nil { - return nil, 0, err - } - // no input provided for this function - - // CUSTOM CODE STARTS HERE - - var output bool // CUSTOM CODE FOR AN OUTPUT - packedOutput, err := PackAreFeeRecipientsAllowedOutput(output) - if err != nil { - return nil, remainingGas, err - } - - // Return the packed output and the remaining gas - return packedOutput, remainingGas, nil -} - -// PackCurrentRewardAddress packs the include selector (first 4 func signature bytes). -// This function is mostly used for tests. -func PackCurrentRewardAddress() ([]byte, error) { - return RewardManagerABI.Pack("currentRewardAddress") -} - -// PackCurrentRewardAddressOutput attempts to pack given rewardAddress of type common.Address -// to conform the ABI outputs. -func PackCurrentRewardAddressOutput(rewardAddress common.Address) ([]byte, error) { - return RewardManagerABI.PackOutput("currentRewardAddress", rewardAddress) -} - -func currentRewardAddress(accessibleState precompile.PrecompileAccessibleState, caller common.Address, addr common.Address, input []byte, suppliedGas uint64, readOnly bool) (ret []byte, remainingGas uint64, err error) { - if remainingGas, err = precompile.DeductGas(suppliedGas, CurrentRewardAddressGasCost); err != nil { - return nil, 0, err - } - // no input provided for this function - - // CUSTOM CODE STARTS HERE - - var output common.Address // CUSTOM CODE FOR AN OUTPUT - packedOutput, err := PackCurrentRewardAddressOutput(output) - if err != nil { - return nil, remainingGas, err - } - - // Return the packed output and the remaining gas - return packedOutput, remainingGas, nil -} - -// PackDisableRewards packs the include selector (first 4 func signature bytes). -// This function is mostly used for tests. -func PackDisableRewards() ([]byte, error) { - return RewardManagerABI.Pack("disableRewards") -} - -func disableRewards(accessibleState precompile.PrecompileAccessibleState, caller common.Address, addr common.Address, input []byte, suppliedGas uint64, readOnly bool) (ret []byte, remainingGas uint64, err error) { - if remainingGas, err = precompile.DeductGas(suppliedGas, DisableRewardsGasCost); err != nil { - return nil, 0, err - } - if readOnly { - return nil, remainingGas, vmerrs.ErrWriteProtection - } - // no input provided for this function - - // Allow list is enabled and DisableRewards is a state-changer function. - // This part of the code restricts the function to be called only by enabled/admin addresses in the allow list. - // You can modify/delete this code if you don't want this function to be restricted by the allow list. - stateDB := accessibleState.GetStateDB() - // Verify that the caller is in the allow list and therefore has the right to modify it - callerStatus := precompile.GetAllowListStatus(stateDB, RewardManagerAddress, caller) - if !callerStatus.IsEnabled() { - return nil, remainingGas, fmt.Errorf("%w: %s", ErrCannotDisableRewards, caller) - } - // allow list code ends here. - - // CUSTOM CODE STARTS HERE - // this function does not return an output, leave this one as is - packedOutput := []byte{} - - // Return the packed output and the remaining gas - return packedOutput, remainingGas, nil -} - -// UnpackSetRewardAddressInput attempts to unpack [input] into the common.Address type argument -// assumes that [input] does not include selector (omits first 4 func signature bytes) -func UnpackSetRewardAddressInput(input []byte) (common.Address, error) { - res, err := RewardManagerABI.UnpackInput("setRewardAddress", input) - if err != nil { - return common.Address{}, err - } - unpacked := *abi.ConvertType(res[0], new(common.Address)).(*common.Address) - return unpacked, nil -} - -// PackSetRewardAddress packs [addr] of type common.Address into the appropriate arguments for setRewardAddress. -// the packed bytes include selector (first 4 func signature bytes). -// This function is mostly used for tests. -func PackSetRewardAddress(addr common.Address) ([]byte, error) { - return RewardManagerABI.Pack("setRewardAddress", addr) -} - -func setRewardAddress(accessibleState precompile.PrecompileAccessibleState, caller common.Address, addr common.Address, input []byte, suppliedGas uint64, readOnly bool) (ret []byte, remainingGas uint64, err error) { - if remainingGas, err = precompile.DeductGas(suppliedGas, SetRewardAddressGasCost); err != nil { - return nil, 0, err - } - if readOnly { - return nil, remainingGas, vmerrs.ErrWriteProtection - } - // attempts to unpack [input] into the arguments to the SetRewardAddressInput. - // Assumes that [input] does not include selector - // You can use unpacked [inputStruct] variable in your code - inputStruct, err := UnpackSetRewardAddressInput(input) - if err != nil { - return nil, remainingGas, err - } - - // Allow list is enabled and SetRewardAddress is a state-changer function. - // This part of the code restricts the function to be called only by enabled/admin addresses in the allow list. - // You can modify/delete this code if you don't want this function to be restricted by the allow list. - stateDB := accessibleState.GetStateDB() - // Verify that the caller is in the allow list and therefore has the right to modify it - callerStatus := precompile.GetAllowListStatus(stateDB, RewardManagerAddress, caller) - if !callerStatus.IsEnabled() { - return nil, remainingGas, fmt.Errorf("%w: %s", ErrCannotSetRewardAddress, caller) - } - // allow list code ends here. - - // CUSTOM CODE STARTS HERE - _ = inputStruct // CUSTOM CODE OPERATES ON INPUT - // this function does not return an output, leave this one as is - packedOutput := []byte{} - - // Return the packed output and the remaining gas - return packedOutput, remainingGas, nil -} - -// createRewardManagerPrecompile returns a StatefulPrecompiledContract with getters and setters for the precompile. -// Access to the getters/setters is controlled by an allow list for [precompileAddr]. -func createRewardManagerPrecompile(precompileAddr common.Address) (precompile.StatefulPrecompiledContract, error) { - var functions []*precompile.StatefulPrecompileFunction - functions = append(functions, precompile.CreateAllowListFunctions(precompileAddr)...) - - abiFunctionMap := map[string]precompile.RunStatefulPrecompileFunc{ - "allowFeeRecipients": allowFeeRecipients, - "areFeeRecipientsAllowed": areFeeRecipientsAllowed, - "currentRewardAddress": currentRewardAddress, - "disableRewards": disableRewards, - "setRewardAddress": setRewardAddress, - } - - for name, function := range abiFunctionMap { - method, ok := RewardManagerABI.Methods[name] - if !ok { - return nil, fmt.Errorf("given method (%s) does not exist in the ABI", name) - } - functions = append(functions, precompile.NewStatefulPrecompileFunction(method.ID, function)) - } - // Construct the contract with no fallback function. - return precompile.NewStatefulPrecompileContract(nil, functions) -} From 535f1c60b8fe840d7805106a16ed8ecebea991fa Mon Sep 17 00:00:00 2001 From: Ceyhun Onur Date: Thu, 29 Dec 2022 21:34:09 +0300 Subject: [PATCH 15/23] upate comments --- accounts/abi/bind/precompile_config_template.go | 13 +++++++------ accounts/abi/bind/precompile_contract_template.go | 13 +++++++------ 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/accounts/abi/bind/precompile_config_template.go b/accounts/abi/bind/precompile_config_template.go index c8903131fb..5b4e9f6fd7 100644 --- a/accounts/abi/bind/precompile_config_template.go +++ b/accounts/abi/bind/precompile_config_template.go @@ -16,16 +16,17 @@ const tmplSourcePrecompileConfigGo = ` /* General guidelines for precompile development: 1- Read the comment and set a suitable contract address in precompile/params.go. E.g: {{.Contract.Type}}Address = common.HexToAddress("ASUITABLEHEXADDRESS") -2- Set gas costs here +2- Set gas costs in contract.go 3- It is recommended to only modify code in the highlighted areas marked with "CUSTOM CODE STARTS HERE". Modifying code outside of these areas should be done with caution and with a deep understanding of how these changes may impact the EVM. Typically, custom codes are required in only those areas. 4- Add your upgradable config in params/precompile_config.go 5- Add your precompile upgrade in params/config.go -6- Add your solidity interface and test contract to contract-examples/contracts -7- Write solidity tests for your precompile in contract-examples/test -8- Create your genesis with your precompile enabled in tests/e2e/genesis/ -9- Create e2e test for your solidity test in tests/e2e/solidity/suites.go -10- Run your e2e precompile Solidity tests with 'E2E=true ./scripts/run.sh' +6- Add your config unit test in {generatedpkg}/config_test.go +7- Add your solidity interface and test contract to contract-examples/contracts +8- Write solidity tests for your precompile in contract-examples/test +9- Create your genesis with your precompile enabled in tests/e2e/genesis/ +10- Create e2e test for your solidity test in tests/e2e/solidity/suites.go +11- Run your e2e precompile Solidity tests with 'E2E=true ./scripts/run.sh' */ diff --git a/accounts/abi/bind/precompile_contract_template.go b/accounts/abi/bind/precompile_contract_template.go index 8656a1507b..6dd7967b3e 100644 --- a/accounts/abi/bind/precompile_contract_template.go +++ b/accounts/abi/bind/precompile_contract_template.go @@ -31,16 +31,17 @@ const tmplSourcePrecompileContractGo = ` /* General guidelines for precompile development: 1- Read the comment and set a suitable contract address in precompile/params.go. E.g: {{.Contract.Type}}Address = common.HexToAddress("ASUITABLEHEXADDRESS") -2- Set gas costs here +2- Set gas costs in contract.go 3- It is recommended to only modify code in the highlighted areas marked with "CUSTOM CODE STARTS HERE". Modifying code outside of these areas should be done with caution and with a deep understanding of how these changes may impact the EVM. Typically, custom codes are required in only those areas. 4- Add your upgradable config in params/precompile_config.go 5- Add your precompile upgrade in params/config.go -6- Add your solidity interface and test contract to contract-examples/contracts -7- Write solidity tests for your precompile in contract-examples/test -8- Create your genesis with your precompile enabled in tests/e2e/genesis/ -9- Create e2e test for your solidity test in tests/e2e/solidity/suites.go -10- Run your e2e precompile Solidity tests with 'E2E=true ./scripts/run.sh' +6- Add your config unit test in {generatedpkg}/config_test.go +7- Add your solidity interface and test contract to contract-examples/contracts +8- Write solidity tests for your precompile in contract-examples/test +9- Create your genesis with your precompile enabled in tests/e2e/genesis/ +10- Create e2e test for your solidity test in tests/e2e/solidity/suites.go +11- Run your e2e precompile Solidity tests with 'E2E=true ./scripts/run.sh' */ From 2ef358778a816b843c997071a53586c31054ba5a Mon Sep 17 00:00:00 2001 From: Ceyhun Onur Date: Thu, 29 Dec 2022 21:41:36 +0300 Subject: [PATCH 16/23] rm test files --- abis/IAllowList.abi | 1 - abis/IRewardManager.abi | 1 - precompile/txallowlist/{contract.go.go => contract.go} | 0 3 files changed, 2 deletions(-) delete mode 100644 abis/IAllowList.abi delete mode 100644 abis/IRewardManager.abi rename precompile/txallowlist/{contract.go.go => contract.go} (100%) diff --git a/abis/IAllowList.abi b/abis/IAllowList.abi deleted file mode 100644 index ea89cd6408..0000000000 --- a/abis/IAllowList.abi +++ /dev/null @@ -1 +0,0 @@ -[{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"readAllowList","outputs":[{"internalType":"uint256","name":"role","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"setAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"setEnabled","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"setNone","outputs":[],"stateMutability":"nonpayable","type":"function"}] \ No newline at end of file diff --git a/abis/IRewardManager.abi b/abis/IRewardManager.abi deleted file mode 100644 index d21d5bdc6b..0000000000 --- a/abis/IRewardManager.abi +++ /dev/null @@ -1 +0,0 @@ -[{"inputs":[],"name":"allowFeeRecipients","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"areFeeRecipientsAllowed","outputs":[{"internalType":"bool","name":"isAllowed","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"currentRewardAddress","outputs":[{"internalType":"address","name":"rewardAddress","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"disableRewards","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"readAllowList","outputs":[{"internalType":"uint256","name":"role","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"setAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"setEnabled","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"setNone","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"setRewardAddress","outputs":[],"stateMutability":"nonpayable","type":"function"}] \ No newline at end of file diff --git a/precompile/txallowlist/contract.go.go b/precompile/txallowlist/contract.go similarity index 100% rename from precompile/txallowlist/contract.go.go rename to precompile/txallowlist/contract.go From af5bc81040dce73477f145fc888bbf7798e04961 Mon Sep 17 00:00:00 2001 From: Ceyhun Onur Date: Tue, 3 Jan 2023 19:50:16 +0300 Subject: [PATCH 17/23] new allowlist package --- .../abi/bind/precompile_config_template.go | 7 - core/genesis_test.go | 3 +- core/stateful_precompile_test.go | 237 +++++++++--------- core/test_blockchain.go | 23 +- plugin/evm/vm_test.go | 29 +-- precompile/{ => allowlist}/allow_list.go | 53 ++-- precompile/{ => allowlist}/allow_list_role.go | 2 +- precompile/deployerallowlist/config.go | 5 +- precompile/deployerallowlist/contract.go | 15 +- precompile/feemanager/config.go | 5 +- precompile/feemanager/contract.go | 13 +- precompile/nativeminter/config.go | 5 +- .../nativeminter/contract_native_minter.go | 13 +- precompile/rewardmanager/config.go | 5 +- precompile/rewardmanager/contract.go | 27 +- precompile/txallowlist/config.go | 9 +- precompile/txallowlist/contract.go | 11 +- 17 files changed, 233 insertions(+), 229 deletions(-) rename precompile/{ => allowlist}/allow_list.go (74%) rename precompile/{ => allowlist}/allow_list_role.go (98%) diff --git a/accounts/abi/bind/precompile_config_template.go b/accounts/abi/bind/precompile_config_template.go index 5b4e9f6fd7..52ff02d268 100644 --- a/accounts/abi/bind/precompile_config_template.go +++ b/accounts/abi/bind/precompile_config_template.go @@ -41,13 +41,6 @@ import ( "github.com/ethereum/go-ethereum/common" ) -// CUSTOM CODE STARTS HERE -// Reference imports to suppress errors from unused imports. This code and any unnecessary imports can be removed. -var ( - _ = big.NewInt - _ = json.Unmarshal -) - {{$contract := .Contract}} var ( _ precompile.StatefulPrecompileConfig = &{{.Contract.Type}}Config{} diff --git a/core/genesis_test.go b/core/genesis_test.go index c9d84ced6c..61baeed669 100644 --- a/core/genesis_test.go +++ b/core/genesis_test.go @@ -39,6 +39,7 @@ import ( "github.com/ava-labs/subnet-evm/ethdb" "github.com/ava-labs/subnet-evm/params" "github.com/ava-labs/subnet-evm/precompile" + "github.com/ava-labs/subnet-evm/precompile/allowlist" "github.com/ava-labs/subnet-evm/precompile/deployerallowlist" "github.com/davecgh/go-spew/spew" "github.com/ethereum/go-ethereum/common" @@ -195,7 +196,7 @@ func TestStatefulPrecompilesConfigure(t *testing.T) { return &config }, assertState: func(t *testing.T, sdb *state.StateDB) { - assert.Equal(t, precompile.AllowListAdmin, deployerallowlist.GetContractDeployerAllowListStatus(sdb, addr), "unexpected allow list status for modified address") + assert.Equal(t, allowlist.AllowListAdmin, deployerallowlist.GetContractDeployerAllowListStatus(sdb, addr), "unexpected allow list status for modified address") assert.Equal(t, uint64(1), sdb.GetNonce(precompile.ContractDeployerAllowListAddress)) }, }, diff --git a/core/stateful_precompile_test.go b/core/stateful_precompile_test.go index b89c587fc8..0fee8976d3 100644 --- a/core/stateful_precompile_test.go +++ b/core/stateful_precompile_test.go @@ -14,6 +14,7 @@ import ( "github.com/ava-labs/subnet-evm/core/state" "github.com/ava-labs/subnet-evm/params" "github.com/ava-labs/subnet-evm/precompile" + "github.com/ava-labs/subnet-evm/precompile/allowlist" "github.com/ava-labs/subnet-evm/precompile/deployerallowlist" "github.com/ava-labs/subnet-evm/precompile/feemanager" "github.com/ava-labs/subnet-evm/precompile/nativeminter" @@ -93,147 +94,147 @@ func TestContractDeployerAllowListRun(t *testing.T) { "set admin": { caller: adminAddr, input: func() []byte { - input, err := precompile.PackModifyAllowList(noRoleAddr, precompile.AllowListAdmin) + input, err := allowlist.PackModifyAllowList(noRoleAddr, allowlist.AllowListAdmin) require.NoError(t, err) return input }, - suppliedGas: precompile.ModifyAllowListGasCost, + suppliedGas: allowlist.ModifyAllowListGasCost, readOnly: false, expectedRes: []byte{}, assertState: func(t *testing.T, state *state.StateDB) { res := deployerallowlist.GetContractDeployerAllowListStatus(state, noRoleAddr) - require.Equal(t, precompile.AllowListAdmin, res) + require.Equal(t, allowlist.AllowListAdmin, res) }, }, "set deployer": { caller: adminAddr, input: func() []byte { - input, err := precompile.PackModifyAllowList(noRoleAddr, precompile.AllowListEnabled) + input, err := allowlist.PackModifyAllowList(noRoleAddr, allowlist.AllowListEnabled) require.NoError(t, err) return input }, - suppliedGas: precompile.ModifyAllowListGasCost, + suppliedGas: allowlist.ModifyAllowListGasCost, readOnly: false, expectedRes: []byte{}, assertState: func(t *testing.T, state *state.StateDB) { res := deployerallowlist.GetContractDeployerAllowListStatus(state, noRoleAddr) - require.Equal(t, precompile.AllowListEnabled, res) + require.Equal(t, allowlist.AllowListEnabled, res) }, }, "set no role": { caller: adminAddr, input: func() []byte { - input, err := precompile.PackModifyAllowList(adminAddr, precompile.AllowListNoRole) + input, err := allowlist.PackModifyAllowList(adminAddr, allowlist.AllowListNoRole) require.NoError(t, err) return input }, - suppliedGas: precompile.ModifyAllowListGasCost, + suppliedGas: allowlist.ModifyAllowListGasCost, readOnly: false, expectedRes: []byte{}, assertState: func(t *testing.T, state *state.StateDB) { res := deployerallowlist.GetContractDeployerAllowListStatus(state, adminAddr) - require.Equal(t, precompile.AllowListNoRole, res) + require.Equal(t, allowlist.AllowListNoRole, res) }, }, "set no role from non-admin": { caller: noRoleAddr, input: func() []byte { - input, err := precompile.PackModifyAllowList(adminAddr, precompile.AllowListNoRole) + input, err := allowlist.PackModifyAllowList(adminAddr, allowlist.AllowListNoRole) require.NoError(t, err) return input }, - suppliedGas: precompile.ModifyAllowListGasCost, + suppliedGas: allowlist.ModifyAllowListGasCost, readOnly: false, - expectedErr: precompile.ErrCannotModifyAllowList.Error(), + expectedErr: allowlist.ErrCannotModifyAllowList.Error(), }, "set deployer from non-admin": { caller: noRoleAddr, input: func() []byte { - input, err := precompile.PackModifyAllowList(adminAddr, precompile.AllowListEnabled) + input, err := allowlist.PackModifyAllowList(adminAddr, allowlist.AllowListEnabled) require.NoError(t, err) return input }, - suppliedGas: precompile.ModifyAllowListGasCost, + suppliedGas: allowlist.ModifyAllowListGasCost, readOnly: false, - expectedErr: precompile.ErrCannotModifyAllowList.Error(), + expectedErr: allowlist.ErrCannotModifyAllowList.Error(), }, "set admin from non-admin": { caller: noRoleAddr, input: func() []byte { - input, err := precompile.PackModifyAllowList(adminAddr, precompile.AllowListAdmin) + input, err := allowlist.PackModifyAllowList(adminAddr, allowlist.AllowListAdmin) require.NoError(t, err) return input }, - suppliedGas: precompile.ModifyAllowListGasCost, + suppliedGas: allowlist.ModifyAllowListGasCost, readOnly: false, - expectedErr: precompile.ErrCannotModifyAllowList.Error(), + expectedErr: allowlist.ErrCannotModifyAllowList.Error(), }, "set no role with readOnly enabled": { caller: adminAddr, input: func() []byte { - input, err := precompile.PackModifyAllowList(adminAddr, precompile.AllowListNoRole) + input, err := allowlist.PackModifyAllowList(adminAddr, allowlist.AllowListNoRole) require.NoError(t, err) return input }, - suppliedGas: precompile.ModifyAllowListGasCost, + suppliedGas: allowlist.ModifyAllowListGasCost, readOnly: true, expectedErr: vmerrs.ErrWriteProtection.Error(), }, "set no role insufficient gas": { caller: adminAddr, input: func() []byte { - input, err := precompile.PackModifyAllowList(adminAddr, precompile.AllowListNoRole) + input, err := allowlist.PackModifyAllowList(adminAddr, allowlist.AllowListNoRole) require.NoError(t, err) return input }, - suppliedGas: precompile.ModifyAllowListGasCost - 1, + suppliedGas: allowlist.ModifyAllowListGasCost - 1, readOnly: false, expectedErr: vmerrs.ErrOutOfGas.Error(), }, "read allow list no role": { caller: noRoleAddr, input: func() []byte { - return precompile.PackReadAllowList(noRoleAddr) + return allowlist.PackReadAllowList(noRoleAddr) }, - suppliedGas: precompile.ReadAllowListGasCost, + suppliedGas: allowlist.ReadAllowListGasCost, readOnly: false, - expectedRes: common.Hash(precompile.AllowListNoRole).Bytes(), + expectedRes: common.Hash(allowlist.AllowListNoRole).Bytes(), assertState: nil, }, "read allow list admin role": { caller: adminAddr, input: func() []byte { - return precompile.PackReadAllowList(noRoleAddr) + return allowlist.PackReadAllowList(noRoleAddr) }, - suppliedGas: precompile.ReadAllowListGasCost, + suppliedGas: allowlist.ReadAllowListGasCost, readOnly: false, - expectedRes: common.Hash(precompile.AllowListNoRole).Bytes(), + expectedRes: common.Hash(allowlist.AllowListNoRole).Bytes(), assertState: nil, }, "read allow list with readOnly enabled": { caller: adminAddr, input: func() []byte { - return precompile.PackReadAllowList(noRoleAddr) + return allowlist.PackReadAllowList(noRoleAddr) }, - suppliedGas: precompile.ReadAllowListGasCost, + suppliedGas: allowlist.ReadAllowListGasCost, readOnly: true, - expectedRes: common.Hash(precompile.AllowListNoRole).Bytes(), + expectedRes: common.Hash(allowlist.AllowListNoRole).Bytes(), assertState: nil, }, "read allow list out of gas": { caller: adminAddr, input: func() []byte { - return precompile.PackReadAllowList(noRoleAddr) + return allowlist.PackReadAllowList(noRoleAddr) }, - suppliedGas: precompile.ReadAllowListGasCost - 1, + suppliedGas: allowlist.ReadAllowListGasCost - 1, readOnly: true, expectedErr: vmerrs.ErrOutOfGas.Error(), }, @@ -244,10 +245,10 @@ func TestContractDeployerAllowListRun(t *testing.T) { require.NoError(t, err) // Set up the state so that each address has the expected permissions at the start. - deployerallowlist.SetContractDeployerAllowListStatus(state, adminAddr, precompile.AllowListAdmin) - deployerallowlist.SetContractDeployerAllowListStatus(state, noRoleAddr, precompile.AllowListNoRole) - require.Equal(t, precompile.AllowListAdmin, deployerallowlist.GetContractDeployerAllowListStatus(state, adminAddr)) - require.Equal(t, precompile.AllowListNoRole, deployerallowlist.GetContractDeployerAllowListStatus(state, noRoleAddr)) + deployerallowlist.SetContractDeployerAllowListStatus(state, adminAddr, allowlist.AllowListAdmin) + deployerallowlist.SetContractDeployerAllowListStatus(state, noRoleAddr, allowlist.AllowListNoRole) + require.Equal(t, allowlist.AllowListAdmin, deployerallowlist.GetContractDeployerAllowListStatus(state, adminAddr)) + require.Equal(t, allowlist.AllowListNoRole, deployerallowlist.GetContractDeployerAllowListStatus(state, noRoleAddr)) blockContext := &mockBlockContext{blockNumber: common.Big0} ret, remainingGas, err := deployerallowlist.ContractDeployerAllowListPrecompile.Run(&mockAccessibleState{state: state, blockContext: blockContext, snowContext: snow.DefaultContextTest()}, test.caller, precompile.ContractDeployerAllowListAddress, test.input(), test.suppliedGas, test.readOnly) @@ -288,148 +289,148 @@ func TestTxAllowListRun(t *testing.T) { "set admin": { caller: adminAddr, input: func() []byte { - input, err := precompile.PackModifyAllowList(noRoleAddr, precompile.AllowListAdmin) + input, err := allowlist.PackModifyAllowList(noRoleAddr, allowlist.AllowListAdmin) require.NoError(t, err) return input }, - suppliedGas: precompile.ModifyAllowListGasCost, + suppliedGas: allowlist.ModifyAllowListGasCost, readOnly: false, expectedRes: []byte{}, assertState: func(t *testing.T, state *state.StateDB) { res := txallowlist.GetTxAllowListStatus(state, noRoleAddr) - require.Equal(t, precompile.AllowListAdmin, res) + require.Equal(t, allowlist.AllowListAdmin, res) }, }, "set allowed": { caller: adminAddr, input: func() []byte { - input, err := precompile.PackModifyAllowList(noRoleAddr, precompile.AllowListEnabled) + input, err := allowlist.PackModifyAllowList(noRoleAddr, allowlist.AllowListEnabled) require.NoError(t, err) return input }, - suppliedGas: precompile.ModifyAllowListGasCost, + suppliedGas: allowlist.ModifyAllowListGasCost, readOnly: false, expectedRes: []byte{}, assertState: func(t *testing.T, state *state.StateDB) { res := txallowlist.GetTxAllowListStatus(state, noRoleAddr) - require.Equal(t, precompile.AllowListEnabled, res) + require.Equal(t, allowlist.AllowListEnabled, res) }, }, "set no role": { caller: adminAddr, input: func() []byte { - input, err := precompile.PackModifyAllowList(adminAddr, precompile.AllowListNoRole) + input, err := allowlist.PackModifyAllowList(adminAddr, allowlist.AllowListNoRole) require.NoError(t, err) return input }, - suppliedGas: precompile.ModifyAllowListGasCost, + suppliedGas: allowlist.ModifyAllowListGasCost, readOnly: false, expectedRes: []byte{}, assertState: func(t *testing.T, state *state.StateDB) { res := txallowlist.GetTxAllowListStatus(state, adminAddr) - require.Equal(t, precompile.AllowListNoRole, res) + require.Equal(t, allowlist.AllowListNoRole, res) }, }, "set no role from non-admin": { caller: noRoleAddr, input: func() []byte { - input, err := precompile.PackModifyAllowList(adminAddr, precompile.AllowListNoRole) + input, err := allowlist.PackModifyAllowList(adminAddr, allowlist.AllowListNoRole) require.NoError(t, err) return input }, - suppliedGas: precompile.ModifyAllowListGasCost, + suppliedGas: allowlist.ModifyAllowListGasCost, readOnly: false, - expectedErr: precompile.ErrCannotModifyAllowList.Error(), + expectedErr: allowlist.ErrCannotModifyAllowList.Error(), }, "set allowed from non-admin": { caller: noRoleAddr, input: func() []byte { - input, err := precompile.PackModifyAllowList(adminAddr, precompile.AllowListEnabled) + input, err := allowlist.PackModifyAllowList(adminAddr, allowlist.AllowListEnabled) require.NoError(t, err) return input }, - suppliedGas: precompile.ModifyAllowListGasCost, + suppliedGas: allowlist.ModifyAllowListGasCost, readOnly: false, - expectedErr: precompile.ErrCannotModifyAllowList.Error(), + expectedErr: allowlist.ErrCannotModifyAllowList.Error(), }, "set admin from non-admin": { caller: noRoleAddr, input: func() []byte { - input, err := precompile.PackModifyAllowList(adminAddr, precompile.AllowListAdmin) + input, err := allowlist.PackModifyAllowList(adminAddr, allowlist.AllowListAdmin) require.NoError(t, err) return input }, - suppliedGas: precompile.ModifyAllowListGasCost, + suppliedGas: allowlist.ModifyAllowListGasCost, readOnly: false, - expectedErr: precompile.ErrCannotModifyAllowList.Error(), + expectedErr: allowlist.ErrCannotModifyAllowList.Error(), }, "set no role with readOnly enabled": { caller: adminAddr, precompileAddr: precompile.TxAllowListAddress, input: func() []byte { - input, err := precompile.PackModifyAllowList(adminAddr, precompile.AllowListNoRole) + input, err := allowlist.PackModifyAllowList(adminAddr, allowlist.AllowListNoRole) require.NoError(t, err) return input }, - suppliedGas: precompile.ModifyAllowListGasCost, + suppliedGas: allowlist.ModifyAllowListGasCost, readOnly: true, expectedErr: vmerrs.ErrWriteProtection.Error(), }, "set no role insufficient gas": { caller: adminAddr, input: func() []byte { - input, err := precompile.PackModifyAllowList(adminAddr, precompile.AllowListNoRole) + input, err := allowlist.PackModifyAllowList(adminAddr, allowlist.AllowListNoRole) require.NoError(t, err) return input }, - suppliedGas: precompile.ModifyAllowListGasCost - 1, + suppliedGas: allowlist.ModifyAllowListGasCost - 1, readOnly: false, expectedErr: vmerrs.ErrOutOfGas.Error(), }, "read allow list no role": { caller: noRoleAddr, input: func() []byte { - return precompile.PackReadAllowList(noRoleAddr) + return allowlist.PackReadAllowList(noRoleAddr) }, - suppliedGas: precompile.ReadAllowListGasCost, + suppliedGas: allowlist.ReadAllowListGasCost, readOnly: false, - expectedRes: common.Hash(precompile.AllowListNoRole).Bytes(), + expectedRes: common.Hash(allowlist.AllowListNoRole).Bytes(), assertState: nil, }, "read allow list admin role": { caller: adminAddr, input: func() []byte { - return precompile.PackReadAllowList(noRoleAddr) + return allowlist.PackReadAllowList(noRoleAddr) }, - suppliedGas: precompile.ReadAllowListGasCost, + suppliedGas: allowlist.ReadAllowListGasCost, readOnly: false, - expectedRes: common.Hash(precompile.AllowListNoRole).Bytes(), + expectedRes: common.Hash(allowlist.AllowListNoRole).Bytes(), assertState: nil, }, "read allow list with readOnly enabled": { caller: adminAddr, input: func() []byte { - return precompile.PackReadAllowList(noRoleAddr) + return allowlist.PackReadAllowList(noRoleAddr) }, - suppliedGas: precompile.ReadAllowListGasCost, + suppliedGas: allowlist.ReadAllowListGasCost, readOnly: true, - expectedRes: common.Hash(precompile.AllowListNoRole).Bytes(), + expectedRes: common.Hash(allowlist.AllowListNoRole).Bytes(), assertState: nil, }, "read allow list out of gas": { caller: adminAddr, input: func() []byte { - return precompile.PackReadAllowList(noRoleAddr) + return allowlist.PackReadAllowList(noRoleAddr) }, - suppliedGas: precompile.ReadAllowListGasCost - 1, + suppliedGas: allowlist.ReadAllowListGasCost - 1, readOnly: true, expectedErr: vmerrs.ErrOutOfGas.Error(), }, @@ -440,8 +441,8 @@ func TestTxAllowListRun(t *testing.T) { require.NoError(t, err) // Set up the state so that each address has the expected permissions at the start. - txallowlist.SetTxAllowListStatus(state, adminAddr, precompile.AllowListAdmin) - require.Equal(t, precompile.AllowListAdmin, txallowlist.GetTxAllowListStatus(state, adminAddr)) + txallowlist.SetTxAllowListStatus(state, adminAddr, allowlist.AllowListAdmin) + require.Equal(t, allowlist.AllowListAdmin, txallowlist.GetTxAllowListStatus(state, adminAddr)) blockContext := &mockBlockContext{blockNumber: common.Big0} ret, remainingGas, err := txallowlist.TxAllowListPrecompile.Run(&mockAccessibleState{state: state, blockContext: blockContext, snowContext: snow.DefaultContextTest()}, test.caller, precompile.TxAllowListAddress, test.input(), test.suppliedGas, test.readOnly) @@ -511,16 +512,16 @@ func TestContractNativeMinterRun(t *testing.T) { "enabled role by config": { caller: noRoleAddr, input: func() []byte { - return precompile.PackReadAllowList(testAddr) + return allowlist.PackReadAllowList(testAddr) }, - suppliedGas: precompile.ReadAllowListGasCost, + suppliedGas: allowlist.ReadAllowListGasCost, readOnly: false, - expectedRes: common.Hash(precompile.AllowListEnabled).Bytes(), + expectedRes: common.Hash(allowlist.AllowListEnabled).Bytes(), assertState: func(t *testing.T, state *state.StateDB) { - require.Equal(t, precompile.AllowListEnabled, nativeminter.GetContractNativeMinterStatus(state, testAddr)) + require.Equal(t, allowlist.AllowListEnabled, nativeminter.GetContractNativeMinterStatus(state, testAddr)) }, config: &nativeminter.ContractNativeMinterConfig{ - AllowListConfig: precompile.AllowListConfig{EnabledAddresses: []common.Address{testAddr}}, + AllowListConfig: allowlist.AllowListConfig{EnabledAddresses: []common.Address{testAddr}}, }, }, "initial mint funds": { @@ -531,11 +532,11 @@ func TestContractNativeMinterRun(t *testing.T) { }, }, input: func() []byte { - return precompile.PackReadAllowList(noRoleAddr) + return allowlist.PackReadAllowList(noRoleAddr) }, - suppliedGas: precompile.ReadAllowListGasCost, + suppliedGas: allowlist.ReadAllowListGasCost, readOnly: false, - expectedRes: common.Hash(precompile.AllowListNoRole).Bytes(), + expectedRes: common.Hash(allowlist.AllowListNoRole).Bytes(), assertState: func(t *testing.T, state *state.StateDB) { require.Equal(t, common.Big2, state.GetBalance(enabledAddr), "expected minted funds") }, @@ -621,59 +622,59 @@ func TestContractNativeMinterRun(t *testing.T) { "read from noRole address": { caller: noRoleAddr, input: func() []byte { - return precompile.PackReadAllowList(noRoleAddr) + return allowlist.PackReadAllowList(noRoleAddr) }, - suppliedGas: precompile.ReadAllowListGasCost, + suppliedGas: allowlist.ReadAllowListGasCost, readOnly: false, - expectedRes: common.Hash(precompile.AllowListNoRole).Bytes(), + expectedRes: common.Hash(allowlist.AllowListNoRole).Bytes(), assertState: func(t *testing.T, state *state.StateDB) {}, }, "read from noRole address readOnly enabled": { caller: noRoleAddr, input: func() []byte { - return precompile.PackReadAllowList(noRoleAddr) + return allowlist.PackReadAllowList(noRoleAddr) }, - suppliedGas: precompile.ReadAllowListGasCost, + suppliedGas: allowlist.ReadAllowListGasCost, readOnly: true, - expectedRes: common.Hash(precompile.AllowListNoRole).Bytes(), + expectedRes: common.Hash(allowlist.AllowListNoRole).Bytes(), assertState: func(t *testing.T, state *state.StateDB) {}, }, "read from noRole address with insufficient gas": { caller: noRoleAddr, input: func() []byte { - return precompile.PackReadAllowList(noRoleAddr) + return allowlist.PackReadAllowList(noRoleAddr) }, - suppliedGas: precompile.ReadAllowListGasCost - 1, + suppliedGas: allowlist.ReadAllowListGasCost - 1, readOnly: false, expectedErr: vmerrs.ErrOutOfGas.Error(), }, "set allow role from admin": { caller: adminAddr, input: func() []byte { - input, err := precompile.PackModifyAllowList(noRoleAddr, precompile.AllowListEnabled) + input, err := allowlist.PackModifyAllowList(noRoleAddr, allowlist.AllowListEnabled) require.NoError(t, err) return input }, - suppliedGas: precompile.ModifyAllowListGasCost, + suppliedGas: allowlist.ModifyAllowListGasCost, readOnly: false, expectedRes: []byte{}, assertState: func(t *testing.T, state *state.StateDB) { res := nativeminter.GetContractNativeMinterStatus(state, noRoleAddr) - require.Equal(t, precompile.AllowListEnabled, res) + require.Equal(t, allowlist.AllowListEnabled, res) }, }, "set allow role from non-admin fails": { caller: enabledAddr, input: func() []byte { - input, err := precompile.PackModifyAllowList(noRoleAddr, precompile.AllowListEnabled) + input, err := allowlist.PackModifyAllowList(noRoleAddr, allowlist.AllowListEnabled) require.NoError(t, err) return input }, - suppliedGas: precompile.ModifyAllowListGasCost, + suppliedGas: allowlist.ModifyAllowListGasCost, readOnly: false, - expectedErr: precompile.ErrCannotModifyAllowList.Error(), + expectedErr: allowlist.ErrCannotModifyAllowList.Error(), }, } { t.Run(name, func(t *testing.T) { @@ -682,12 +683,12 @@ func TestContractNativeMinterRun(t *testing.T) { require.NoError(t, err) // Set up the state so that each address has the expected permissions at the start. - nativeminter.SetContractNativeMinterStatus(state, adminAddr, precompile.AllowListAdmin) - nativeminter.SetContractNativeMinterStatus(state, enabledAddr, precompile.AllowListEnabled) - nativeminter.SetContractNativeMinterStatus(state, noRoleAddr, precompile.AllowListNoRole) - require.Equal(t, precompile.AllowListAdmin, nativeminter.GetContractNativeMinterStatus(state, adminAddr)) - require.Equal(t, precompile.AllowListEnabled, nativeminter.GetContractNativeMinterStatus(state, enabledAddr)) - require.Equal(t, precompile.AllowListNoRole, nativeminter.GetContractNativeMinterStatus(state, noRoleAddr)) + nativeminter.SetContractNativeMinterStatus(state, adminAddr, allowlist.AllowListAdmin) + nativeminter.SetContractNativeMinterStatus(state, enabledAddr, allowlist.AllowListEnabled) + nativeminter.SetContractNativeMinterStatus(state, noRoleAddr, allowlist.AllowListNoRole) + require.Equal(t, allowlist.AllowListAdmin, nativeminter.GetContractNativeMinterStatus(state, adminAddr)) + require.Equal(t, allowlist.AllowListEnabled, nativeminter.GetContractNativeMinterStatus(state, enabledAddr)) + require.Equal(t, allowlist.AllowListNoRole, nativeminter.GetContractNativeMinterStatus(state, noRoleAddr)) blockContext := &mockBlockContext{blockNumber: common.Big0} if test.config != nil { @@ -913,30 +914,30 @@ func TestFeeConfigManagerRun(t *testing.T) { "set allow role from admin": { caller: adminAddr, input: func() []byte { - input, err := precompile.PackModifyAllowList(noRoleAddr, precompile.AllowListEnabled) + input, err := allowlist.PackModifyAllowList(noRoleAddr, allowlist.AllowListEnabled) require.NoError(t, err) return input }, - suppliedGas: precompile.ModifyAllowListGasCost, + suppliedGas: allowlist.ModifyAllowListGasCost, readOnly: false, expectedRes: []byte{}, assertState: func(t *testing.T, state *state.StateDB) { res := feemanager.GetFeeConfigManagerStatus(state, noRoleAddr) - require.Equal(t, precompile.AllowListEnabled, res) + require.Equal(t, allowlist.AllowListEnabled, res) }, }, "set allow role from non-admin fails": { caller: enabledAddr, input: func() []byte { - input, err := precompile.PackModifyAllowList(noRoleAddr, precompile.AllowListEnabled) + input, err := allowlist.PackModifyAllowList(noRoleAddr, allowlist.AllowListEnabled) require.NoError(t, err) return input }, - suppliedGas: precompile.ModifyAllowListGasCost, + suppliedGas: allowlist.ModifyAllowListGasCost, readOnly: false, - expectedErr: precompile.ErrCannotModifyAllowList.Error(), + expectedErr: allowlist.ErrCannotModifyAllowList.Error(), }, } { t.Run(name, func(t *testing.T) { @@ -945,9 +946,9 @@ func TestFeeConfigManagerRun(t *testing.T) { require.NoError(t, err) // Set up the state so that each address has the expected permissions at the start. - feemanager.SetFeeConfigManagerStatus(state, adminAddr, precompile.AllowListAdmin) - feemanager.SetFeeConfigManagerStatus(state, enabledAddr, precompile.AllowListEnabled) - feemanager.SetFeeConfigManagerStatus(state, noRoleAddr, precompile.AllowListNoRole) + feemanager.SetFeeConfigManagerStatus(state, adminAddr, allowlist.AllowListAdmin) + feemanager.SetFeeConfigManagerStatus(state, enabledAddr, allowlist.AllowListEnabled) + feemanager.SetFeeConfigManagerStatus(state, noRoleAddr, allowlist.AllowListNoRole) if test.preCondition != nil { test.preCondition(t, state) @@ -1233,30 +1234,30 @@ func TestRewardManagerRun(t *testing.T) { "set allow role from admin": { caller: adminAddr, input: func() []byte { - input, err := precompile.PackModifyAllowList(noRoleAddr, precompile.AllowListEnabled) + input, err := allowlist.PackModifyAllowList(noRoleAddr, allowlist.AllowListEnabled) require.NoError(t, err) return input }, - suppliedGas: precompile.ModifyAllowListGasCost, + suppliedGas: allowlist.ModifyAllowListGasCost, readOnly: false, expectedRes: []byte{}, assertState: func(t *testing.T, state *state.StateDB) { res := rewardmanager.GetRewardManagerAllowListStatus(state, noRoleAddr) - require.Equal(t, precompile.AllowListEnabled, res) + require.Equal(t, allowlist.AllowListEnabled, res) }, }, "set allow role from non-admin fails": { caller: enabledAddr, input: func() []byte { - input, err := precompile.PackModifyAllowList(noRoleAddr, precompile.AllowListEnabled) + input, err := allowlist.PackModifyAllowList(noRoleAddr, allowlist.AllowListEnabled) require.NoError(t, err) return input }, - suppliedGas: precompile.ModifyAllowListGasCost, + suppliedGas: allowlist.ModifyAllowListGasCost, readOnly: false, - expectedErr: precompile.ErrCannotModifyAllowList.Error(), + expectedErr: allowlist.ErrCannotModifyAllowList.Error(), }, } { t.Run(name, func(t *testing.T) { @@ -1265,9 +1266,9 @@ func TestRewardManagerRun(t *testing.T) { require.NoError(t, err) // Set up the state so that each address has the expected permissions at the start. - rewardmanager.SetRewardManagerAllowListStatus(state, adminAddr, precompile.AllowListAdmin) - rewardmanager.SetRewardManagerAllowListStatus(state, enabledAddr, precompile.AllowListEnabled) - rewardmanager.SetRewardManagerAllowListStatus(state, noRoleAddr, precompile.AllowListNoRole) + rewardmanager.SetRewardManagerAllowListStatus(state, adminAddr, allowlist.AllowListAdmin) + rewardmanager.SetRewardManagerAllowListStatus(state, enabledAddr, allowlist.AllowListEnabled) + rewardmanager.SetRewardManagerAllowListStatus(state, noRoleAddr, allowlist.AllowListNoRole) if test.preCondition != nil { test.preCondition(t, state) diff --git a/core/test_blockchain.go b/core/test_blockchain.go index c1254ee005..1f66a44b82 100644 --- a/core/test_blockchain.go +++ b/core/test_blockchain.go @@ -17,6 +17,7 @@ import ( "github.com/ava-labs/subnet-evm/ethdb" "github.com/ava-labs/subnet-evm/params" "github.com/ava-labs/subnet-evm/precompile" + "github.com/ava-labs/subnet-evm/precompile/allowlist" "github.com/ava-labs/subnet-evm/precompile/deployerallowlist" "github.com/ava-labs/subnet-evm/precompile/feemanager" "github.com/ethereum/go-ethereum/common" @@ -1589,7 +1590,7 @@ func TestStatefulPrecompiles(t *testing.T, create func(db ethdb.Database, chainC "allow list": { addTx: func(gen *BlockGen) { feeCap := new(big.Int).Add(gen.BaseFee(), tip) - input, err := precompile.PackModifyAllowList(addr2, precompile.AllowListAdmin) + input, err := allowlist.PackModifyAllowList(addr2, allowlist.AllowListAdmin) if err != nil { t.Fatal(err) } @@ -1612,23 +1613,23 @@ func TestStatefulPrecompiles(t *testing.T, create func(db ethdb.Database, chainC }, verifyState: func(sdb *state.StateDB) error { res := deployerallowlist.GetContractDeployerAllowListStatus(sdb, addr1) - if precompile.AllowListAdmin != res { - return fmt.Errorf("unexpected allow list status for addr1 %s, expected %s", res, precompile.AllowListAdmin) + if allowlist.AllowListAdmin != res { + return fmt.Errorf("unexpected allow list status for addr1 %s, expected %s", res, allowlist.AllowListAdmin) } res = deployerallowlist.GetContractDeployerAllowListStatus(sdb, addr2) - if precompile.AllowListAdmin != res { - return fmt.Errorf("unexpected allow list status for addr2 %s, expected %s", res, precompile.AllowListAdmin) + if allowlist.AllowListAdmin != res { + return fmt.Errorf("unexpected allow list status for addr2 %s, expected %s", res, allowlist.AllowListAdmin) } return nil }, verifyGenesis: func(sdb *state.StateDB) { res := deployerallowlist.GetContractDeployerAllowListStatus(sdb, addr1) - if precompile.AllowListAdmin != res { - t.Fatalf("unexpected allow list status for addr1 %s, expected %s", res, precompile.AllowListAdmin) + if allowlist.AllowListAdmin != res { + t.Fatalf("unexpected allow list status for addr1 %s, expected %s", res, allowlist.AllowListAdmin) } res = deployerallowlist.GetContractDeployerAllowListStatus(sdb, addr2) - if precompile.AllowListNoRole != res { - t.Fatalf("unexpected allow list status for addr2 %s, expected %s", res, precompile.AllowListNoRole) + if allowlist.AllowListNoRole != res { + t.Fatalf("unexpected allow list status for addr2 %s, expected %s", res, allowlist.AllowListNoRole) } }, }, @@ -1658,7 +1659,7 @@ func TestStatefulPrecompiles(t *testing.T, create func(db ethdb.Database, chainC }, verifyState: func(sdb *state.StateDB) error { res := feemanager.GetFeeConfigManagerStatus(sdb, addr1) - assert.Equal(precompile.AllowListAdmin, res) + assert.Equal(allowlist.AllowListAdmin, res) storedConfig := feemanager.GetStoredFeeConfig(sdb) assert.EqualValues(testFeeConfig, storedConfig) @@ -1670,7 +1671,7 @@ func TestStatefulPrecompiles(t *testing.T, create func(db ethdb.Database, chainC }, verifyGenesis: func(sdb *state.StateDB) { res := feemanager.GetFeeConfigManagerStatus(sdb, addr1) - assert.Equal(precompile.AllowListAdmin, res) + assert.Equal(allowlist.AllowListAdmin, res) feeConfig, _, err := blockchain.GetFeeConfigAt(blockchain.Genesis().Header()) assert.NoError(err) diff --git a/plugin/evm/vm_test.go b/plugin/evm/vm_test.go index 986c56b38f..6034d3f958 100644 --- a/plugin/evm/vm_test.go +++ b/plugin/evm/vm_test.go @@ -20,6 +20,7 @@ import ( "github.com/ava-labs/subnet-evm/commontype" "github.com/ava-labs/subnet-evm/metrics" "github.com/ava-labs/subnet-evm/precompile" + "github.com/ava-labs/subnet-evm/precompile/allowlist" "github.com/ava-labs/subnet-evm/precompile/deployerallowlist" "github.com/ava-labs/subnet-evm/precompile/feemanager" "github.com/ava-labs/subnet-evm/precompile/rewardmanager" @@ -2143,8 +2144,8 @@ func TestBuildAllowListActivationBlock(t *testing.T) { t.Fatal(err) } role := deployerallowlist.GetContractDeployerAllowListStatus(genesisState, testEthAddrs[0]) - if role != precompile.AllowListNoRole { - t.Fatalf("Expected allow list status to be set to no role: %s, but found: %s", precompile.AllowListNoRole, role) + if role != allowlist.AllowListNoRole { + t.Fatalf("Expected allow list status to be set to no role: %s, but found: %s", allowlist.AllowListNoRole, role) } // Send basic transaction to construct a simple block and confirm that the precompile state configuration in the worker behaves correctly. @@ -2173,8 +2174,8 @@ func TestBuildAllowListActivationBlock(t *testing.T) { t.Fatal(err) } role = deployerallowlist.GetContractDeployerAllowListStatus(blkState, testEthAddrs[0]) - if role != precompile.AllowListAdmin { - t.Fatalf("Expected allow list status to be set to Admin: %s, but found: %s", precompile.AllowListAdmin, role) + if role != allowlist.AllowListAdmin { + t.Fatalf("Expected allow list status to be set to Admin: %s, but found: %s", allowlist.AllowListAdmin, role) } } @@ -2208,12 +2209,12 @@ func TestTxAllowListSuccessfulTx(t *testing.T) { // Check that address 0 is whitelisted and address 1 is not role := txallowlist.GetTxAllowListStatus(genesisState, testEthAddrs[0]) - if role != precompile.AllowListAdmin { - t.Fatalf("Expected allow list status to be set to admin: %s, but found: %s", precompile.AllowListAdmin, role) + if role != allowlist.AllowListAdmin { + t.Fatalf("Expected allow list status to be set to admin: %s, but found: %s", allowlist.AllowListAdmin, role) } role = txallowlist.GetTxAllowListStatus(genesisState, testEthAddrs[1]) - if role != precompile.AllowListNoRole { - t.Fatalf("Expected allow list status to be set to no role: %s, but found: %s", precompile.AllowListNoRole, role) + if role != allowlist.AllowListNoRole { + t.Fatalf("Expected allow list status to be set to no role: %s, but found: %s", allowlist.AllowListNoRole, role) } // Submit a successful transaction @@ -2303,12 +2304,12 @@ func TestTxAllowListDisablePrecompile(t *testing.T) { // Check that address 0 is whitelisted and address 1 is not role := txallowlist.GetTxAllowListStatus(genesisState, testEthAddrs[0]) - if role != precompile.AllowListAdmin { - t.Fatalf("Expected allow list status to be set to admin: %s, but found: %s", precompile.AllowListAdmin, role) + if role != allowlist.AllowListAdmin { + t.Fatalf("Expected allow list status to be set to admin: %s, but found: %s", allowlist.AllowListAdmin, role) } role = txallowlist.GetTxAllowListStatus(genesisState, testEthAddrs[1]) - if role != precompile.AllowListNoRole { - t.Fatalf("Expected allow list status to be set to no role: %s, but found: %s", precompile.AllowListNoRole, role) + if role != allowlist.AllowListNoRole { + t.Fatalf("Expected allow list status to be set to no role: %s, but found: %s", allowlist.AllowListNoRole, role) } // Submit a successful transaction @@ -2412,11 +2413,11 @@ func TestFeeManagerChangeFee(t *testing.T) { // Check that address 0 is whitelisted and address 1 is not role := feemanager.GetFeeConfigManagerStatus(genesisState, testEthAddrs[0]) - if role != precompile.AllowListAdmin { + if role != allowlist.AllowListAdmin { t.Fatalf("Expected fee manager list status to be set to admin: %s, but found: %s", precompile.FeeConfigManagerAddress, role) } role = feemanager.GetFeeConfigManagerStatus(genesisState, testEthAddrs[1]) - if role != precompile.AllowListNoRole { + if role != allowlist.AllowListNoRole { t.Fatalf("Expected fee manager list status to be set to no role: %s, but found: %s", precompile.FeeConfigManagerAddress, role) } // Contract is initialized but no preconfig is given, reader should return genesis fee config diff --git a/precompile/allow_list.go b/precompile/allowlist/allow_list.go similarity index 74% rename from precompile/allow_list.go rename to precompile/allowlist/allow_list.go index 9e1f867a51..ced37ed530 100644 --- a/precompile/allow_list.go +++ b/precompile/allowlist/allow_list.go @@ -1,13 +1,14 @@ // (c) 2019-2020, Ava Labs, Inc. All rights reserved. // See the file LICENSE for licensing terms. -package precompile +package allowlist import ( "errors" "fmt" "math/big" + "github.com/ava-labs/subnet-evm/precompile" "github.com/ava-labs/subnet-evm/vmerrs" "github.com/ethereum/go-ethereum/common" ) @@ -18,8 +19,8 @@ const ( SetNoneFuncKey = "setNone" ReadAllowListFuncKey = "readAllowList" - ModifyAllowListGasCost = WriteGasCostPerSlot - ReadAllowListGasCost = ReadGasCostPerSlot + ModifyAllowListGasCost = precompile.WriteGasCostPerSlot + ReadAllowListGasCost = precompile.ReadGasCostPerSlot ) var ( @@ -28,10 +29,10 @@ var ( AllowListAdmin AllowListRole = AllowListRole(common.BigToHash(big.NewInt(2))) // Admin - allowed to modify both the admin and deployer list as well as deploy contracts // AllowList function signatures - setAdminSignature = CalculateFunctionSelector("setAdmin(address)") - setEnabledSignature = CalculateFunctionSelector("setEnabled(address)") - setNoneSignature = CalculateFunctionSelector("setNone(address)") - readAllowListSignature = CalculateFunctionSelector("readAllowList(address)") + setAdminSignature = precompile.CalculateFunctionSelector("setAdmin(address)") + setEnabledSignature = precompile.CalculateFunctionSelector("setEnabled(address)") + setNoneSignature = precompile.CalculateFunctionSelector("setNone(address)") + readAllowListSignature = precompile.CalculateFunctionSelector("readAllowList(address)") // Error returned when an invalid write is attempted ErrCannotModifyAllowList = errors.New("non-admin cannot modify allow list") @@ -46,7 +47,7 @@ type AllowListConfig struct { // Configure initializes the address space of [precompileAddr] by initializing the role of each of // the addresses in [AllowListAdmins]. -func (c *AllowListConfig) Configure(state StateDB, precompileAddr common.Address) error { +func (c *AllowListConfig) Configure(state precompile.StateDB, precompileAddr common.Address) error { for _, enabledAddr := range c.EnabledAddresses { SetAllowListRole(state, precompileAddr, enabledAddr, AllowListEnabled) } @@ -114,7 +115,7 @@ func (c *AllowListConfig) Verify() error { // GetAllowListStatus returns the allow list role of [address] for the precompile // at [precompileAddr] -func GetAllowListStatus(state StateDB, precompileAddr common.Address, address common.Address) AllowListRole { +func GetAllowListStatus(state precompile.StateDB, precompileAddr common.Address, address common.Address) AllowListRole { // Generate the state key for [address] addressKey := address.Hash() return AllowListRole(state.GetState(precompileAddr, addressKey)) @@ -123,7 +124,7 @@ func GetAllowListStatus(state StateDB, precompileAddr common.Address, address co // SetAllowListRole sets the permissions of [address] to [role] for the precompile // at [precompileAddr]. // assumes [role] has already been verified as valid. -func SetAllowListRole(stateDB StateDB, precompileAddr, address common.Address, role AllowListRole) { +func SetAllowListRole(stateDB precompile.StateDB, precompileAddr, address common.Address, role AllowListRole) { // Generate the state key for [address] addressKey := address.Hash() // Assign [role] to the address @@ -139,7 +140,7 @@ func SetAllowListRole(stateDB StateDB, precompileAddr, address common.Address, r // selector that should be encoded in the input. func PackModifyAllowList(address common.Address, role AllowListRole) ([]byte, error) { // function selector (4 bytes) + hash for address - input := make([]byte, 0, SelectorLen+common.HashLength) + input := make([]byte, 0, precompile.SelectorLen+common.HashLength) switch role { case AllowListAdmin: @@ -158,7 +159,7 @@ func PackModifyAllowList(address common.Address, role AllowListRole) ([]byte, er // PackReadAllowList packs [address] into the input data to the read allow list function func PackReadAllowList(address common.Address) []byte { - input := make([]byte, 0, SelectorLen+common.HashLength) + input := make([]byte, 0, precompile.SelectorLen+common.HashLength) input = append(input, readAllowListSignature...) input = append(input, address.Hash().Bytes()...) return input @@ -166,9 +167,9 @@ func PackReadAllowList(address common.Address) []byte { // createAllowListRoleSetter returns an execution function for setting the allow list status of the input address argument to [role]. // This execution function is speciifc to [precompileAddr]. -func createAllowListRoleSetter(precompileAddr common.Address, role AllowListRole) RunStatefulPrecompileFunc { - return func(evm PrecompileAccessibleState, callerAddr, addr common.Address, input []byte, suppliedGas uint64, readOnly bool) (ret []byte, remainingGas uint64, err error) { - if remainingGas, err = DeductGas(suppliedGas, ModifyAllowListGasCost); err != nil { +func createAllowListRoleSetter(precompileAddr common.Address, role AllowListRole) precompile.RunStatefulPrecompileFunc { + return func(evm precompile.PrecompileAccessibleState, callerAddr, addr common.Address, input []byte, suppliedGas uint64, readOnly bool) (ret []byte, remainingGas uint64, err error) { + if remainingGas, err = precompile.DeductGas(suppliedGas, ModifyAllowListGasCost); err != nil { return nil, 0, err } @@ -199,9 +200,9 @@ func createAllowListRoleSetter(precompileAddr common.Address, role AllowListRole // createReadAllowList returns an execution function that reads the allow list for the given [precompileAddr]. // The execution function parses the input into a single address and returns the 32 byte hash that specifies the // designated role of that address -func createReadAllowList(precompileAddr common.Address) RunStatefulPrecompileFunc { - return func(evm PrecompileAccessibleState, callerAddr common.Address, addr common.Address, input []byte, suppliedGas uint64, readOnly bool) (ret []byte, remainingGas uint64, err error) { - if remainingGas, err = DeductGas(suppliedGas, ReadAllowListGasCost); err != nil { +func createReadAllowList(precompileAddr common.Address) precompile.RunStatefulPrecompileFunc { + return func(evm precompile.PrecompileAccessibleState, callerAddr common.Address, addr common.Address, input []byte, suppliedGas uint64, readOnly bool) (ret []byte, remainingGas uint64, err error) { + if remainingGas, err = precompile.DeductGas(suppliedGas, ReadAllowListGasCost); err != nil { return nil, 0, err } @@ -217,10 +218,10 @@ func createReadAllowList(precompileAddr common.Address) RunStatefulPrecompileFun } // createAllowListPrecompile returns a StatefulPrecompiledContract with R/W control of an allow list at [precompileAddr] -func CreateAllowListPrecompile(precompileAddr common.Address) StatefulPrecompiledContract { +func CreateAllowListPrecompile(precompileAddr common.Address) precompile.StatefulPrecompiledContract { // Construct the contract with no fallback function. allowListFuncs := CreateAllowListFunctions(precompileAddr) - contract, err := NewStatefulPrecompileContract(nil, allowListFuncs) + contract, err := precompile.NewStatefulPrecompileContract(nil, allowListFuncs) // TODO Change this to be returned as an error after refactoring this precompile // to use the new precompile template. if err != nil { @@ -229,11 +230,11 @@ func CreateAllowListPrecompile(precompileAddr common.Address) StatefulPrecompile return contract } -func CreateAllowListFunctions(precompileAddr common.Address) []*StatefulPrecompileFunction { - setAdmin := NewStatefulPrecompileFunction(setAdminSignature, createAllowListRoleSetter(precompileAddr, AllowListAdmin)) - setEnabled := NewStatefulPrecompileFunction(setEnabledSignature, createAllowListRoleSetter(precompileAddr, AllowListEnabled)) - setNone := NewStatefulPrecompileFunction(setNoneSignature, createAllowListRoleSetter(precompileAddr, AllowListNoRole)) - read := NewStatefulPrecompileFunction(readAllowListSignature, createReadAllowList(precompileAddr)) +func CreateAllowListFunctions(precompileAddr common.Address) []*precompile.StatefulPrecompileFunction { + setAdmin := precompile.NewStatefulPrecompileFunction(setAdminSignature, createAllowListRoleSetter(precompileAddr, AllowListAdmin)) + setEnabled := precompile.NewStatefulPrecompileFunction(setEnabledSignature, createAllowListRoleSetter(precompileAddr, AllowListEnabled)) + setNone := precompile.NewStatefulPrecompileFunction(setNoneSignature, createAllowListRoleSetter(precompileAddr, AllowListNoRole)) + read := precompile.NewStatefulPrecompileFunction(readAllowListSignature, createReadAllowList(precompileAddr)) - return []*StatefulPrecompileFunction{setAdmin, setEnabled, setNone, read} + return []*precompile.StatefulPrecompileFunction{setAdmin, setEnabled, setNone, read} } diff --git a/precompile/allow_list_role.go b/precompile/allowlist/allow_list_role.go similarity index 98% rename from precompile/allow_list_role.go rename to precompile/allowlist/allow_list_role.go index 0c815d0819..7e59f8420e 100644 --- a/precompile/allow_list_role.go +++ b/precompile/allowlist/allow_list_role.go @@ -1,7 +1,7 @@ // (c) 2019-2020, Ava Labs, Inc. All rights reserved. // See the file LICENSE for licensing terms. -package precompile +package allowlist import "github.com/ethereum/go-ethereum/common" diff --git a/precompile/deployerallowlist/config.go b/precompile/deployerallowlist/config.go index 34ce2ded8a..07b8e27dc2 100644 --- a/precompile/deployerallowlist/config.go +++ b/precompile/deployerallowlist/config.go @@ -8,6 +8,7 @@ import ( "math/big" "github.com/ava-labs/subnet-evm/precompile" + "github.com/ava-labs/subnet-evm/precompile/allowlist" "github.com/ethereum/go-ethereum/common" ) @@ -16,7 +17,7 @@ var _ precompile.StatefulPrecompileConfig = &ContractDeployerAllowListConfig{} // ContractDeployerAllowListConfig wraps [AllowListConfig] and uses it to implement the StatefulPrecompileConfig // interface while adding in the contract deployer specific precompile address. type ContractDeployerAllowListConfig struct { - precompile.AllowListConfig + allowlist.AllowListConfig precompile.UpgradeableConfig } @@ -24,7 +25,7 @@ type ContractDeployerAllowListConfig struct { // ContractDeployerAllowList with [admins] and [enableds] as members of the allowlist. func NewContractDeployerAllowListConfig(blockTimestamp *big.Int, admins []common.Address, enableds []common.Address) *ContractDeployerAllowListConfig { return &ContractDeployerAllowListConfig{ - AllowListConfig: precompile.AllowListConfig{ + AllowListConfig: allowlist.AllowListConfig{ AllowListAdmins: admins, EnabledAddresses: enableds, }, diff --git a/precompile/deployerallowlist/contract.go b/precompile/deployerallowlist/contract.go index df464452b3..4fb4ace7b9 100644 --- a/precompile/deployerallowlist/contract.go +++ b/precompile/deployerallowlist/contract.go @@ -5,23 +5,22 @@ package deployerallowlist import ( "github.com/ava-labs/subnet-evm/precompile" + "github.com/ava-labs/subnet-evm/precompile/allowlist" "github.com/ethereum/go-ethereum/common" ) -var ( - // Singleton StatefulPrecompiledContract for W/R access to the contract deployer allow list. - ContractDeployerAllowListPrecompile precompile.StatefulPrecompiledContract = precompile.CreateAllowListPrecompile(precompile.ContractDeployerAllowListAddress) -) +// Singleton StatefulPrecompiledContract for W/R access to the contract deployer allow list. +var ContractDeployerAllowListPrecompile precompile.StatefulPrecompiledContract = allowlist.CreateAllowListPrecompile(precompile.ContractDeployerAllowListAddress) // GetContractDeployerAllowListStatus returns the role of [address] for the contract deployer // allow list. -func GetContractDeployerAllowListStatus(stateDB precompile.StateDB, address common.Address) precompile.AllowListRole { - return precompile.GetAllowListStatus(stateDB, precompile.ContractDeployerAllowListAddress, address) +func GetContractDeployerAllowListStatus(stateDB precompile.StateDB, address common.Address) allowlist.AllowListRole { + return allowlist.GetAllowListStatus(stateDB, precompile.ContractDeployerAllowListAddress, address) } // SetContractDeployerAllowListStatus sets the permissions of [address] to [role] for the // contract deployer allow list. // assumes [role] has already been verified as valid. -func SetContractDeployerAllowListStatus(stateDB precompile.StateDB, address common.Address, role precompile.AllowListRole) { - precompile.SetAllowListRole(stateDB, precompile.ContractDeployerAllowListAddress, address, role) +func SetContractDeployerAllowListStatus(stateDB precompile.StateDB, address common.Address, role allowlist.AllowListRole) { + allowlist.SetAllowListRole(stateDB, precompile.ContractDeployerAllowListAddress, address, role) } diff --git a/precompile/feemanager/config.go b/precompile/feemanager/config.go index 8de349ca83..bee3acf785 100644 --- a/precompile/feemanager/config.go +++ b/precompile/feemanager/config.go @@ -10,13 +10,14 @@ import ( "github.com/ava-labs/subnet-evm/commontype" "github.com/ava-labs/subnet-evm/precompile" + "github.com/ava-labs/subnet-evm/precompile/allowlist" "github.com/ethereum/go-ethereum/common" ) // FeeConfigManagerConfig wraps [AllowListConfig] and uses it to implement the StatefulPrecompileConfig // interface while adding in the FeeConfigManager specific precompile address. type FeeConfigManagerConfig struct { - precompile.AllowListConfig // Config for the fee config manager allow list + allowlist.AllowListConfig // Config for the fee config manager allow list precompile.UpgradeableConfig InitialFeeConfig *commontype.FeeConfig `json:"initialFeeConfig,omitempty"` // initial fee config to be immediately activated } @@ -25,7 +26,7 @@ type FeeConfigManagerConfig struct { // FeeConfigManager with the given [admins] and [enableds] as members of the allowlist with [initialConfig] as initial fee config if specified. func NewFeeManagerConfig(blockTimestamp *big.Int, admins []common.Address, enableds []common.Address, initialConfig *commontype.FeeConfig) *FeeConfigManagerConfig { return &FeeConfigManagerConfig{ - AllowListConfig: precompile.AllowListConfig{ + AllowListConfig: allowlist.AllowListConfig{ AllowListAdmins: admins, EnabledAddresses: enableds, }, diff --git a/precompile/feemanager/contract.go b/precompile/feemanager/contract.go index 996920203e..760303ecde 100644 --- a/precompile/feemanager/contract.go +++ b/precompile/feemanager/contract.go @@ -10,6 +10,7 @@ import ( "github.com/ava-labs/subnet-evm/commontype" "github.com/ava-labs/subnet-evm/precompile" + "github.com/ava-labs/subnet-evm/precompile/allowlist" "github.com/ava-labs/subnet-evm/vmerrs" "github.com/ethereum/go-ethereum/common" ) @@ -53,14 +54,14 @@ var ( ) // GetFeeConfigManagerStatus returns the role of [address] for the fee config manager list. -func GetFeeConfigManagerStatus(stateDB precompile.StateDB, address common.Address) precompile.AllowListRole { - return precompile.GetAllowListStatus(stateDB, precompile.FeeConfigManagerAddress, address) +func GetFeeConfigManagerStatus(stateDB precompile.StateDB, address common.Address) allowlist.AllowListRole { + return allowlist.GetAllowListStatus(stateDB, precompile.FeeConfigManagerAddress, address) } // SetFeeConfigManagerStatus sets the permissions of [address] to [role] for the // fee config manager list. assumes [role] has already been verified as valid. -func SetFeeConfigManagerStatus(stateDB precompile.StateDB, address common.Address, role precompile.AllowListRole) { - precompile.SetAllowListRole(stateDB, precompile.FeeConfigManagerAddress, address, role) +func SetFeeConfigManagerStatus(stateDB precompile.StateDB, address common.Address, role allowlist.AllowListRole) { + allowlist.SetAllowListRole(stateDB, precompile.FeeConfigManagerAddress, address, role) } // PackGetFeeConfigInput packs the getFeeConfig signature @@ -238,7 +239,7 @@ func setFeeConfig(accessibleState precompile.PrecompileAccessibleState, caller c stateDB := accessibleState.GetStateDB() // Verify that the caller is in the allow list and therefore has the right to modify it - callerStatus := precompile.GetAllowListStatus(stateDB, precompile.FeeConfigManagerAddress, caller) + callerStatus := allowlist.GetAllowListStatus(stateDB, precompile.FeeConfigManagerAddress, caller) if !callerStatus.IsEnabled() { return nil, remainingGas, fmt.Errorf("%w: %s", ErrCannotChangeFee, caller) } @@ -286,7 +287,7 @@ func getFeeConfigLastChangedAt(accessibleState precompile.PrecompileAccessibleSt // with getters and setters for the chain's fee config. Access to the getters/setters // is controlled by an allow list for [precompileAddr]. func createFeeConfigManagerPrecompile(precompileAddr common.Address) precompile.StatefulPrecompiledContract { - feeConfigManagerFunctions := precompile.CreateAllowListFunctions(precompileAddr) + feeConfigManagerFunctions := allowlist.CreateAllowListFunctions(precompileAddr) setFeeConfigFunc := precompile.NewStatefulPrecompileFunction(setFeeConfigSignature, setFeeConfig) getFeeConfigFunc := precompile.NewStatefulPrecompileFunction(getFeeConfigSignature, getFeeConfig) diff --git a/precompile/nativeminter/config.go b/precompile/nativeminter/config.go index 9ba6644b6e..51194dcc88 100644 --- a/precompile/nativeminter/config.go +++ b/precompile/nativeminter/config.go @@ -9,6 +9,7 @@ import ( "math/big" "github.com/ava-labs/subnet-evm/precompile" + "github.com/ava-labs/subnet-evm/precompile/allowlist" "github.com/ava-labs/subnet-evm/utils" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/math" @@ -19,7 +20,7 @@ var _ precompile.StatefulPrecompileConfig = &ContractNativeMinterConfig{} // ContractNativeMinterConfig wraps [AllowListConfig] and uses it to implement the StatefulPrecompileConfig // interface while adding in the ContractNativeMinter specific precompile address. type ContractNativeMinterConfig struct { - precompile.AllowListConfig + allowlist.AllowListConfig precompile.UpgradeableConfig InitialMint map[common.Address]*math.HexOrDecimal256 `json:"initialMint,omitempty"` // initial mint config to be immediately minted } @@ -28,7 +29,7 @@ type ContractNativeMinterConfig struct { // ContractNativeMinter with the given [admins] and [enableds] as members of the allowlist. Also mints balances according to [initialMint] when the upgrade activates. func NewContractNativeMinterConfig(blockTimestamp *big.Int, admins []common.Address, enableds []common.Address, initialMint map[common.Address]*math.HexOrDecimal256) *ContractNativeMinterConfig { return &ContractNativeMinterConfig{ - AllowListConfig: precompile.AllowListConfig{ + AllowListConfig: allowlist.AllowListConfig{ AllowListAdmins: admins, EnabledAddresses: enableds, }, diff --git a/precompile/nativeminter/contract_native_minter.go b/precompile/nativeminter/contract_native_minter.go index aa3d19eedb..23931a375e 100644 --- a/precompile/nativeminter/contract_native_minter.go +++ b/precompile/nativeminter/contract_native_minter.go @@ -9,6 +9,7 @@ import ( "math/big" "github.com/ava-labs/subnet-evm/precompile" + "github.com/ava-labs/subnet-evm/precompile/allowlist" "github.com/ava-labs/subnet-evm/vmerrs" "github.com/ethereum/go-ethereum/common" ) @@ -31,14 +32,14 @@ var ( ) // GetContractNativeMinterStatus returns the role of [address] for the minter list. -func GetContractNativeMinterStatus(stateDB precompile.StateDB, address common.Address) precompile.AllowListRole { - return precompile.GetAllowListStatus(stateDB, precompile.ContractNativeMinterAddress, address) +func GetContractNativeMinterStatus(stateDB precompile.StateDB, address common.Address) allowlist.AllowListRole { + return allowlist.GetAllowListStatus(stateDB, precompile.ContractNativeMinterAddress, address) } // SetContractNativeMinterStatus sets the permissions of [address] to [role] for the // minter list. assumes [role] has already been verified as valid. -func SetContractNativeMinterStatus(stateDB precompile.StateDB, address common.Address, role precompile.AllowListRole) { - precompile.SetAllowListRole(stateDB, precompile.ContractNativeMinterAddress, address, role) +func SetContractNativeMinterStatus(stateDB precompile.StateDB, address common.Address, role allowlist.AllowListRole) { + allowlist.SetAllowListRole(stateDB, precompile.ContractNativeMinterAddress, address, role) } // PackMintInput packs [address] and [amount] into the appropriate arguments for minting operation. @@ -83,7 +84,7 @@ func mintNativeCoin(accessibleState precompile.PrecompileAccessibleState, caller stateDB := accessibleState.GetStateDB() // Verify that the caller is in the allow list and therefore has the right to modify it - callerStatus := precompile.GetAllowListStatus(stateDB, precompile.ContractNativeMinterAddress, caller) + callerStatus := allowlist.GetAllowListStatus(stateDB, precompile.ContractNativeMinterAddress, caller) if !callerStatus.IsEnabled() { return nil, remainingGas, fmt.Errorf("%w: %s", ErrCannotMint, caller) } @@ -100,7 +101,7 @@ func mintNativeCoin(accessibleState precompile.PrecompileAccessibleState, caller // createNativeMinterPrecompile returns a StatefulPrecompiledContract with R/W control of an allow list at [precompileAddr] and a native coin minter. func createNativeMinterPrecompile(precompileAddr common.Address) precompile.StatefulPrecompiledContract { - enabledFuncs := precompile.CreateAllowListFunctions(precompileAddr) + enabledFuncs := allowlist.CreateAllowListFunctions(precompileAddr) mintFunc := precompile.NewStatefulPrecompileFunction(mintSignature, mintNativeCoin) diff --git a/precompile/rewardmanager/config.go b/precompile/rewardmanager/config.go index 6b85f6fedb..0be23b61ab 100644 --- a/precompile/rewardmanager/config.go +++ b/precompile/rewardmanager/config.go @@ -11,6 +11,7 @@ import ( "math/big" "github.com/ava-labs/subnet-evm/precompile" + "github.com/ava-labs/subnet-evm/precompile/allowlist" "github.com/ethereum/go-ethereum/common" ) @@ -56,7 +57,7 @@ func (i *InitialRewardConfig) Configure(state precompile.StateDB) error { // RewardManagerConfig implements the StatefulPrecompileConfig // interface while adding in the RewardManager specific precompile config. type RewardManagerConfig struct { - precompile.AllowListConfig + allowlist.AllowListConfig precompile.UpgradeableConfig InitialRewardConfig *InitialRewardConfig `json:"initialRewardConfig,omitempty"` } @@ -65,7 +66,7 @@ type RewardManagerConfig struct { // RewardManager with the given [admins] and [enableds] as members of the allowlist with [initialConfig] as initial rewards config if specified. func NewRewardManagerConfig(blockTimestamp *big.Int, admins []common.Address, enableds []common.Address, initialConfig *InitialRewardConfig) *RewardManagerConfig { return &RewardManagerConfig{ - AllowListConfig: precompile.AllowListConfig{ + AllowListConfig: allowlist.AllowListConfig{ AllowListAdmins: admins, EnabledAddresses: enableds, }, diff --git a/precompile/rewardmanager/contract.go b/precompile/rewardmanager/contract.go index b7b13aba94..0c95aee847 100644 --- a/precompile/rewardmanager/contract.go +++ b/precompile/rewardmanager/contract.go @@ -14,6 +14,7 @@ import ( "github.com/ava-labs/subnet-evm/accounts/abi" "github.com/ava-labs/subnet-evm/constants" "github.com/ava-labs/subnet-evm/precompile" + "github.com/ava-labs/subnet-evm/precompile/allowlist" "github.com/ava-labs/subnet-evm/vmerrs" _ "embed" @@ -22,11 +23,11 @@ import ( ) const ( - AllowFeeRecipientsGasCost uint64 = (precompile.WriteGasCostPerSlot) + precompile.ReadAllowListGasCost // write 1 slot + read allow list - AreFeeRecipientsAllowedGasCost uint64 = precompile.ReadAllowListGasCost - CurrentRewardAddressGasCost uint64 = precompile.ReadAllowListGasCost - DisableRewardsGasCost uint64 = (precompile.WriteGasCostPerSlot) + precompile.ReadAllowListGasCost // write 1 slot + read allow list - SetRewardAddressGasCost uint64 = (precompile.WriteGasCostPerSlot) + precompile.ReadAllowListGasCost // write 1 slot + read allow list + AllowFeeRecipientsGasCost uint64 = (precompile.WriteGasCostPerSlot) + allowlist.ReadAllowListGasCost // write 1 slot + read allow list + AreFeeRecipientsAllowedGasCost uint64 = allowlist.ReadAllowListGasCost + CurrentRewardAddressGasCost uint64 = allowlist.ReadAllowListGasCost + DisableRewardsGasCost uint64 = (precompile.WriteGasCostPerSlot) + allowlist.ReadAllowListGasCost // write 1 slot + read allow list + SetRewardAddressGasCost uint64 = (precompile.WriteGasCostPerSlot) + allowlist.ReadAllowListGasCost // write 1 slot + read allow list ) // Singleton StatefulPrecompiledContract and signatures. @@ -64,14 +65,14 @@ func init() { } // GetRewardManagerAllowListStatus returns the role of [address] for the RewardManager list. -func GetRewardManagerAllowListStatus(stateDB precompile.StateDB, address common.Address) precompile.AllowListRole { - return precompile.GetAllowListStatus(stateDB, precompile.RewardManagerAddress, address) +func GetRewardManagerAllowListStatus(stateDB precompile.StateDB, address common.Address) allowlist.AllowListRole { + return allowlist.GetAllowListStatus(stateDB, precompile.RewardManagerAddress, address) } // SetRewardManagerAllowListStatus sets the permissions of [address] to [role] for the // RewardManager list. Assumes [role] has already been verified as valid. -func SetRewardManagerAllowListStatus(stateDB precompile.StateDB, address common.Address, role precompile.AllowListRole) { - precompile.SetAllowListRole(stateDB, precompile.RewardManagerAddress, address, role) +func SetRewardManagerAllowListStatus(stateDB precompile.StateDB, address common.Address, role allowlist.AllowListRole) { + allowlist.SetAllowListRole(stateDB, precompile.RewardManagerAddress, address, role) } // PackAllowFeeRecipients packs the function selector (first 4 func signature bytes). @@ -104,7 +105,7 @@ func allowFeeRecipients(accessibleState precompile.PrecompileAccessibleState, ca // You can modify/delete this code if you don't want this function to be restricted by the allow list. stateDB := accessibleState.GetStateDB() // Verify that the caller is in the allow list and therefore has the right to modify it - callerStatus := precompile.GetAllowListStatus(stateDB, precompile.RewardManagerAddress, caller) + callerStatus := allowlist.GetAllowListStatus(stateDB, precompile.RewardManagerAddress, caller) if !callerStatus.IsEnabled() { return nil, remainingGas, fmt.Errorf("%w: %s", ErrCannotAllowFeeRecipients, caller) } @@ -216,7 +217,7 @@ func setRewardAddress(accessibleState precompile.PrecompileAccessibleState, call // You can modify/delete this code if you don't want this function to be restricted by the allow list. stateDB := accessibleState.GetStateDB() // Verify that the caller is in the allow list and therefore has the right to modify it - callerStatus := precompile.GetAllowListStatus(stateDB, precompile.RewardManagerAddress, caller) + callerStatus := allowlist.GetAllowListStatus(stateDB, precompile.RewardManagerAddress, caller) if !callerStatus.IsEnabled() { return nil, remainingGas, fmt.Errorf("%w: %s", ErrCannotSetRewardAddress, caller) } @@ -269,7 +270,7 @@ func disableRewards(accessibleState precompile.PrecompileAccessibleState, caller // You can modify/delete this code if you don't want this function to be restricted by the allow list. stateDB := accessibleState.GetStateDB() // Verify that the caller is in the allow list and therefore has the right to modify it - callerStatus := precompile.GetAllowListStatus(stateDB, precompile.RewardManagerAddress, caller) + callerStatus := allowlist.GetAllowListStatus(stateDB, precompile.RewardManagerAddress, caller) if !callerStatus.IsEnabled() { return nil, remainingGas, fmt.Errorf("%w: %s", ErrCannotDisableRewards, caller) } @@ -286,7 +287,7 @@ func disableRewards(accessibleState precompile.PrecompileAccessibleState, caller // Access to the getters/setters is controlled by an allow list for [precompileAddr]. func createRewardManagerPrecompile(precompileAddr common.Address) (precompile.StatefulPrecompiledContract, error) { var functions []*precompile.StatefulPrecompileFunction - functions = append(functions, precompile.CreateAllowListFunctions(precompileAddr)...) + functions = append(functions, allowlist.CreateAllowListFunctions(precompileAddr)...) abiFunctionMap := map[string]precompile.RunStatefulPrecompileFunc{ "allowFeeRecipients": allowFeeRecipients, "areFeeRecipientsAllowed": areFeeRecipientsAllowed, diff --git a/precompile/txallowlist/config.go b/precompile/txallowlist/config.go index 0551835405..88435c977b 100644 --- a/precompile/txallowlist/config.go +++ b/precompile/txallowlist/config.go @@ -8,17 +8,16 @@ import ( "math/big" "github.com/ava-labs/subnet-evm/precompile" + "github.com/ava-labs/subnet-evm/precompile/allowlist" "github.com/ethereum/go-ethereum/common" ) -var ( - _ precompile.StatefulPrecompileConfig = &TxAllowListConfig{} -) +var _ precompile.StatefulPrecompileConfig = &TxAllowListConfig{} // TxAllowListConfig wraps [AllowListConfig] and uses it to implement the StatefulPrecompileConfig // interface while adding in the TxAllowList specific precompile address. type TxAllowListConfig struct { - precompile.AllowListConfig + allowlist.AllowListConfig precompile.UpgradeableConfig } @@ -26,7 +25,7 @@ type TxAllowListConfig struct { // TxAllowList with the given [admins] and [enableds] as members of the allowlist. func NewTxAllowListConfig(blockTimestamp *big.Int, admins []common.Address, enableds []common.Address) *TxAllowListConfig { return &TxAllowListConfig{ - AllowListConfig: precompile.AllowListConfig{ + AllowListConfig: allowlist.AllowListConfig{ AllowListAdmins: admins, EnabledAddresses: enableds, }, diff --git a/precompile/txallowlist/contract.go b/precompile/txallowlist/contract.go index d1e9ed4b3c..cc00973a7e 100644 --- a/precompile/txallowlist/contract.go +++ b/precompile/txallowlist/contract.go @@ -7,26 +7,27 @@ import ( "errors" "github.com/ava-labs/subnet-evm/precompile" + "github.com/ava-labs/subnet-evm/precompile/allowlist" "github.com/ethereum/go-ethereum/common" ) var ( _ precompile.StatefulPrecompileConfig = &TxAllowListConfig{} // Singleton StatefulPrecompiledContract for W/R access to the contract deployer allow list. - TxAllowListPrecompile precompile.StatefulPrecompiledContract = precompile.CreateAllowListPrecompile(precompile.TxAllowListAddress) + TxAllowListPrecompile precompile.StatefulPrecompiledContract = allowlist.CreateAllowListPrecompile(precompile.TxAllowListAddress) ErrSenderAddressNotAllowListed = errors.New("cannot issue transaction from non-allow listed address") ) // GetTxAllowListStatus returns the role of [address] for the contract deployer // allow list. -func GetTxAllowListStatus(stateDB precompile.StateDB, address common.Address) precompile.AllowListRole { - return precompile.GetAllowListStatus(stateDB, precompile.TxAllowListAddress, address) +func GetTxAllowListStatus(stateDB precompile.StateDB, address common.Address) allowlist.AllowListRole { + return allowlist.GetAllowListStatus(stateDB, precompile.TxAllowListAddress, address) } // SetTxAllowListStatus sets the permissions of [address] to [role] for the // tx allow list. // assumes [role] has already been verified as valid. -func SetTxAllowListStatus(stateDB precompile.StateDB, address common.Address, role precompile.AllowListRole) { - precompile.SetAllowListRole(stateDB, precompile.TxAllowListAddress, address, role) +func SetTxAllowListStatus(stateDB precompile.StateDB, address common.Address, role allowlist.AllowListRole) { + allowlist.SetAllowListRole(stateDB, precompile.TxAllowListAddress, address, role) } From 0aae0749e725ad9c6630869042b0764ee3c7b348 Mon Sep 17 00:00:00 2001 From: Ceyhun Onur Date: Wed, 4 Jan 2023 10:40:18 +0300 Subject: [PATCH 18/23] Update precompile/utils.go Co-authored-by: Darioush Jalali --- precompile/utils.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/precompile/utils.go b/precompile/utils.go index dfbe4affd6..7adbaa6546 100644 --- a/precompile/utils.go +++ b/precompile/utils.go @@ -42,7 +42,7 @@ func PackOrderedHashesWithSelector(dst []byte, functionSelector []byte, hashes [ return PackOrderedHashes(dst[len(functionSelector):], hashes) } -// packOrderedHashes packs the ordered list of [hashes] into the [dst] byte buffer. +// PackOrderedHashes packs the ordered list of [hashes] into the [dst] byte buffer. // assumes that [dst] has sufficient space to pack [hashes] or else this function will panic. func PackOrderedHashes(dst []byte, hashes []common.Hash) error { if len(dst) != len(hashes)*common.HashLength { From 79bba2a84c5b6dda45042d624f1dfdbfb01331fe Mon Sep 17 00:00:00 2001 From: Ceyhun Onur Date: Wed, 4 Jan 2023 10:42:48 +0300 Subject: [PATCH 19/23] Update precompile/nativeminter/contract_native_minter.go Co-authored-by: Darioush Jalali --- precompile/nativeminter/contract_native_minter.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/precompile/nativeminter/contract_native_minter.go b/precompile/nativeminter/contract_native_minter.go index 23931a375e..2ac58afbd9 100644 --- a/precompile/nativeminter/contract_native_minter.go +++ b/precompile/nativeminter/contract_native_minter.go @@ -99,7 +99,8 @@ func mintNativeCoin(accessibleState precompile.PrecompileAccessibleState, caller return []byte{}, remainingGas, nil } -// createNativeMinterPrecompile returns a StatefulPrecompiledContract with R/W control of an allow list at [precompileAddr] and a native coin minter. +// createNativeMinterPrecompile returns a StatefulPrecompiledContract for native coin minting. The precompile +// is accessed controlled by an allow list at [precompileAddr]. func createNativeMinterPrecompile(precompileAddr common.Address) precompile.StatefulPrecompiledContract { enabledFuncs := allowlist.CreateAllowListFunctions(precompileAddr) From 1bd589ff858c3dd086ca230852a70882520546f7 Mon Sep 17 00:00:00 2001 From: Ceyhun Onur Date: Wed, 4 Jan 2023 10:43:12 +0300 Subject: [PATCH 20/23] Update precompile/nativeminter/contract_native_minter.go Co-authored-by: Darioush Jalali --- precompile/nativeminter/contract_native_minter.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/precompile/nativeminter/contract_native_minter.go b/precompile/nativeminter/contract_native_minter.go index 2ac58afbd9..30566dd94c 100644 --- a/precompile/nativeminter/contract_native_minter.go +++ b/precompile/nativeminter/contract_native_minter.go @@ -109,7 +109,7 @@ func createNativeMinterPrecompile(precompileAddr common.Address) precompile.Stat enabledFuncs = append(enabledFuncs, mintFunc) // Construct the contract with no fallback function. contract, err := precompile.NewStatefulPrecompileContract(nil, enabledFuncs) - // Change this to be returned as an error after refactoring this precompile + // TODO: Change this to be returned as an error after refactoring this precompile // to use the new precompile template. if err != nil { panic(err) From bd0c54e68728f50d8c427ec615d8ec0d5069f42b Mon Sep 17 00:00:00 2001 From: Ceyhun Onur Date: Wed, 4 Jan 2023 10:45:21 +0300 Subject: [PATCH 21/23] Update precompile/utils.go Co-authored-by: Darioush Jalali --- precompile/utils.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/precompile/utils.go b/precompile/utils.go index 7adbaa6546..f03e89bc50 100644 --- a/precompile/utils.go +++ b/precompile/utils.go @@ -34,7 +34,7 @@ func DeductGas(suppliedGas uint64, requiredGas uint64) (uint64, error) { return suppliedGas - requiredGas, nil } -// packOrderedHashesWithSelector packs the function selector and ordered list of hashes into [dst] +// PackOrderedHashesWithSelector packs the function selector and ordered list of hashes into [dst] // byte slice. // assumes that [dst] has sufficient room for [functionSelector] and [hashes]. func PackOrderedHashesWithSelector(dst []byte, functionSelector []byte, hashes []common.Hash) error { From f4c399e9d3f272183fc54b43c722662671d1e1c5 Mon Sep 17 00:00:00 2001 From: Ceyhun Onur Date: Wed, 4 Jan 2023 10:45:33 +0300 Subject: [PATCH 22/23] Update precompile/nativeminter/contract_native_minter.go Co-authored-by: Darioush Jalali --- precompile/nativeminter/contract_native_minter.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/precompile/nativeminter/contract_native_minter.go b/precompile/nativeminter/contract_native_minter.go index 30566dd94c..7098c252cb 100644 --- a/precompile/nativeminter/contract_native_minter.go +++ b/precompile/nativeminter/contract_native_minter.go @@ -83,7 +83,7 @@ func mintNativeCoin(accessibleState precompile.PrecompileAccessibleState, caller } stateDB := accessibleState.GetStateDB() - // Verify that the caller is in the allow list and therefore has the right to modify it + // Verify that the caller is in the allow list callerStatus := allowlist.GetAllowListStatus(stateDB, precompile.ContractNativeMinterAddress, caller) if !callerStatus.IsEnabled() { return nil, remainingGas, fmt.Errorf("%w: %s", ErrCannotMint, caller) From 988439c783da2bdddb3ed5de2f04fc38c197491d Mon Sep 17 00:00:00 2001 From: Ceyhun Onur Date: Wed, 4 Jan 2023 10:48:46 +0300 Subject: [PATCH 23/23] fix nits --- plugin/evm/vm_test.go | 3 +-- precompile/nativeminter/config_test.go | 1 - .../nativeminter/{contract_native_minter.go => contract.go} | 0 precompile/rewardmanager/config.go | 4 ++-- precompile/txallowlist/contract.go | 6 +++--- 5 files changed, 6 insertions(+), 8 deletions(-) rename precompile/nativeminter/{contract_native_minter.go => contract.go} (100%) diff --git a/plugin/evm/vm_test.go b/plugin/evm/vm_test.go index 6034d3f958..c96ce4b31b 100644 --- a/plugin/evm/vm_test.go +++ b/plugin/evm/vm_test.go @@ -31,7 +31,6 @@ import ( "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/log" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/ava-labs/avalanchego/api/keystore" @@ -2431,7 +2430,7 @@ func TestFeeManagerChangeFee(t *testing.T) { testHighFeeConfig.MinBaseFee = big.NewInt(28_000_000_000) data, err := feemanager.PackSetFeeConfig(testHighFeeConfig) - assert.NoError(t, err) + require.NoError(t, err) tx := types.NewTx(&types.DynamicFeeTx{ ChainID: genesis.Config.ChainID, diff --git a/precompile/nativeminter/config_test.go b/precompile/nativeminter/config_test.go index 99c87f4aad..9eb2441454 100644 --- a/precompile/nativeminter/config_test.go +++ b/precompile/nativeminter/config_test.go @@ -126,7 +126,6 @@ func TestEqualContractNativeMinterConfig(t *testing.T) { }), expected: false, }, - { name: "same config", config: NewContractNativeMinterConfig(big.NewInt(3), admins, nil, diff --git a/precompile/nativeminter/contract_native_minter.go b/precompile/nativeminter/contract.go similarity index 100% rename from precompile/nativeminter/contract_native_minter.go rename to precompile/nativeminter/contract.go diff --git a/precompile/rewardmanager/config.go b/precompile/rewardmanager/config.go index 0be23b61ab..640198da30 100644 --- a/precompile/rewardmanager/config.go +++ b/precompile/rewardmanager/config.go @@ -31,12 +31,12 @@ func (i *InitialRewardConfig) Verify() error { } } -func (c *InitialRewardConfig) Equal(other *InitialRewardConfig) bool { +func (i *InitialRewardConfig) Equal(other *InitialRewardConfig) bool { if other == nil { return false } - return c.AllowFeeRecipients == other.AllowFeeRecipients && c.RewardAddress == other.RewardAddress + return i.AllowFeeRecipients == other.AllowFeeRecipients && i.RewardAddress == other.RewardAddress } func (i *InitialRewardConfig) Configure(state precompile.StateDB) error { diff --git a/precompile/txallowlist/contract.go b/precompile/txallowlist/contract.go index cc00973a7e..2917e9b9c4 100644 --- a/precompile/txallowlist/contract.go +++ b/precompile/txallowlist/contract.go @@ -13,14 +13,14 @@ import ( var ( _ precompile.StatefulPrecompileConfig = &TxAllowListConfig{} - // Singleton StatefulPrecompiledContract for W/R access to the contract deployer allow list. + + // Singleton StatefulPrecompiledContract for W/R access to the tx allow list. TxAllowListPrecompile precompile.StatefulPrecompiledContract = allowlist.CreateAllowListPrecompile(precompile.TxAllowListAddress) ErrSenderAddressNotAllowListed = errors.New("cannot issue transaction from non-allow listed address") ) -// GetTxAllowListStatus returns the role of [address] for the contract deployer -// allow list. +// GetTxAllowListStatus returns the role of [address] for the allow list. func GetTxAllowListStatus(stateDB precompile.StateDB, address common.Address) allowlist.AllowListRole { return allowlist.GetAllowListStatus(stateDB, precompile.TxAllowListAddress, address) }