diff --git a/x/evm/keeper/keeper.go b/x/evm/keeper/keeper.go index 2d3e90a175..7a87b4f791 100644 --- a/x/evm/keeper/keeper.go +++ b/x/evm/keeper/keeper.go @@ -72,7 +72,7 @@ type Keeper struct { hooks types.EvmHooks // custom stateless precompiled smart contracts - customPrecompiles evm.PrecompiledContracts + getPrecompilesExtended func(ctx sdk.Context, evm *vm.EVM) evm.PrecompiledContracts // evm constructor function evmConstructor evm.Constructor @@ -89,7 +89,7 @@ func NewKeeper( bankKeeper types.BankKeeper, sk types.StakingKeeper, fmk types.FeeMarketKeeper, - customPrecompiles evm.PrecompiledContracts, + getPrecompilesExtended func(ctx sdk.Context, evm *vm.EVM) evm.PrecompiledContracts, evmConstructor evm.Constructor, tracer string, ss paramstypes.Subspace, @@ -106,18 +106,18 @@ func NewKeeper( // NOTE: we pass in the parameter space to the CommitStateDB in order to use custom denominations for the EVM operations return &Keeper{ - cdc: cdc, - authority: authority, - accountKeeper: ak, - bankKeeper: bankKeeper, - stakingKeeper: sk, - feeMarketKeeper: fmk, - storeKey: storeKey, - transientKey: transientKey, - customPrecompiles: customPrecompiles, - evmConstructor: evmConstructor, - tracer: tracer, - ss: ss, + cdc: cdc, + authority: authority, + accountKeeper: ak, + bankKeeper: bankKeeper, + stakingKeeper: sk, + feeMarketKeeper: fmk, + storeKey: storeKey, + transientKey: transientKey, + getPrecompilesExtended: getPrecompilesExtended, + evmConstructor: evmConstructor, + tracer: tracer, + ss: ss, } } diff --git a/x/evm/keeper/state_transition.go b/x/evm/keeper/state_transition.go index 5327052a37..4624b90367 100644 --- a/x/evm/keeper/state_transition.go +++ b/x/evm/keeper/state_transition.go @@ -70,7 +70,7 @@ func (k *Keeper) NewEVM( tracer = k.Tracer(ctx, msg, cfg.ChainConfig) } vmConfig := k.VMConfig(ctx, msg, cfg, tracer) - return k.evmConstructor(blockCtx, txCtx, stateDB, cfg.ChainConfig, vmConfig, k.customPrecompiles) + return k.evmConstructor(ctx, blockCtx, txCtx, stateDB, cfg.ChainConfig, vmConfig, k.getPrecompilesExtended) } // GetHashFn implements vm.GetHashFunc for Ethermint. It handles 3 cases: diff --git a/x/evm/vm/geth/geth.go b/x/evm/vm/geth/geth.go index 6563342413..b0ff5d9b6c 100644 --- a/x/evm/vm/geth/geth.go +++ b/x/evm/vm/geth/geth.go @@ -16,9 +16,10 @@ package geth import ( - "math/big" + "bytes" + "sort" - "github.com/ethereum/go-ethereum/common" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/params" @@ -39,16 +40,33 @@ type EVM struct { // the default precompiled contracts and the EVM concrete implementation from // geth. func NewEVM( + ctx sdk.Context, blockCtx vm.BlockContext, txCtx vm.TxContext, stateDB vm.StateDB, chainConfig *params.ChainConfig, config vm.Config, - _ evm.PrecompiledContracts, // unused + getPrecompilesExtended func(ctx sdk.Context, evm *vm.EVM) evm.PrecompiledContracts, ) evm.EVM { - return &EVM{ + newEvm := &EVM{ EVM: vm.NewEVM(blockCtx, txCtx, stateDB, chainConfig, config), } + + precompiles := GetPrecompiles(chainConfig, blockCtx.BlockNumber) + activePrecompiles := GetActivePrecompiles(chainConfig, blockCtx.BlockNumber) + + customPrecompiles := getPrecompilesExtended(ctx, newEvm.EVM) + for k, v := range customPrecompiles { + precompiles[k] = v + activePrecompiles = append(activePrecompiles, v.Address()) + } + + sort.SliceStable(activePrecompiles, func(i, j int) bool { + return bytes.Compare(activePrecompiles[i].Bytes(), activePrecompiles[j].Bytes()) < 0 + }) + + newEvm.WithPrecompiles(precompiles, activePrecompiles) + return newEvm } // Context returns the EVM's Block Context @@ -65,31 +83,3 @@ func (e EVM) TxContext() vm.TxContext { func (e EVM) Config() vm.Config { return e.EVM.Config } - -// Precompile returns the precompiled contract associated with the given address -// and the current chain configuration. If the contract cannot be found it returns -// nil. -func (e EVM) Precompile(addr common.Address) (p vm.PrecompiledContract, found bool) { - precompiles := GetPrecompiles(e.ChainConfig(), e.EVM.Context.BlockNumber) - p, found = precompiles[addr] - return p, found -} - -// ActivePrecompiles returns a list of all the active precompiled contract addresses -// for the current chain configuration. -func (EVM) ActivePrecompiles(rules params.Rules) []common.Address { - return vm.DefaultActivePrecompiles(rules) -} - -// RunPrecompiledContract runs a stateless precompiled contract and ignores the address and -// value arguments. It uses the RunPrecompiledContract function from the geth vm package. -func (e EVM) RunPrecompiledContract( - p vm.PrecompiledContract, - caller vm.ContractRef, - input []byte, - suppliedGas uint64, - value *big.Int, // value arg is unused - readOnly bool, -) (ret []byte, remainingGas uint64, err error) { - return e.EVM.RunPrecompiledContract(p, caller, input, suppliedGas, value, readOnly) -} diff --git a/x/evm/vm/geth/precompiles.go b/x/evm/vm/geth/precompiles.go index 5226a3283d..cfe18ab743 100644 --- a/x/evm/vm/geth/precompiles.go +++ b/x/evm/vm/geth/precompiles.go @@ -18,6 +18,7 @@ package geth import ( "math/big" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/params" @@ -27,16 +28,41 @@ import ( // GetPrecompiles returns all the precompiled contracts defined given the // current chain configuration and block height. func GetPrecompiles(cfg *params.ChainConfig, blockNumber *big.Int) evm.PrecompiledContracts { - var precompiles evm.PrecompiledContracts + var defaulfPrecompiles evm.PrecompiledContracts switch { case cfg.IsBerlin(blockNumber): - precompiles = vm.PrecompiledContractsBerlin + defaulfPrecompiles = vm.PrecompiledContractsBerlin case cfg.IsIstanbul(blockNumber): - precompiles = vm.PrecompiledContractsIstanbul + defaulfPrecompiles = vm.PrecompiledContractsIstanbul case cfg.IsByzantium(blockNumber): - precompiles = vm.PrecompiledContractsByzantium + defaulfPrecompiles = vm.PrecompiledContractsByzantium default: - precompiles = vm.PrecompiledContractsHomestead + defaulfPrecompiles = vm.PrecompiledContractsHomestead + } + precompiles := make(evm.PrecompiledContracts, len(defaulfPrecompiles)) + for address, contract := range defaulfPrecompiles { + precompiles[address] = contract } return precompiles } + +// GetActivePrecompiles returns all the precompiled active contracts defined given the +// current chain configuration and block height. +func GetActivePrecompiles(cfg *params.ChainConfig, blockNumber *big.Int) []common.Address { + var defaultActivePrecompiles []common.Address + switch { + case cfg.IsBerlin(blockNumber): + defaultActivePrecompiles = vm.PrecompiledAddressesBerlin + case cfg.IsIstanbul(blockNumber): + defaultActivePrecompiles = vm.PrecompiledAddressesIstanbul + case cfg.IsByzantium(blockNumber): + defaultActivePrecompiles = vm.PrecompiledAddressesByzantium + default: + defaultActivePrecompiles = vm.PrecompiledAddressesHomestead + } + + activePrecompiles := make([]common.Address, len(defaultActivePrecompiles)) + copy(activePrecompiles, defaultActivePrecompiles) + + return defaultActivePrecompiles +} diff --git a/x/evm/vm/interface.go b/x/evm/vm/interface.go index 631bcc3c3e..9648dfe036 100644 --- a/x/evm/vm/interface.go +++ b/x/evm/vm/interface.go @@ -18,6 +18,7 @@ package vm import ( "math/big" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/params" @@ -27,11 +28,6 @@ import ( // PrecompiledContracts defines a map of address -> precompiled contract type PrecompiledContracts map[common.Address]vm.PrecompiledContract -type StatefulPrecompiledContract interface { - vm.PrecompiledContract - RunStateful(evm EVM, addr common.Address, input []byte, value *big.Int) (ret []byte, err error) -} - // EVM defines the interface for the Ethereum Virtual Machine used by the EVM module. type EVM interface { Config() vm.Config @@ -73,10 +69,11 @@ type EVM interface { // Constructor defines the function used to instantiate the EVM on // each state transition. type Constructor func( + ctx sdk.Context, blockCtx vm.BlockContext, txCtx vm.TxContext, stateDB vm.StateDB, chainConfig *params.ChainConfig, config vm.Config, - customPrecompiles PrecompiledContracts, + getPrecompilesExtended func(ctx sdk.Context, evm *vm.EVM) PrecompiledContracts, ) EVM