From d43a82c59b181065e45a8f035e0840d25fb7e8b2 Mon Sep 17 00:00:00 2001 From: Loredana Cirstea Date: Sat, 5 Nov 2022 22:55:47 +0100 Subject: [PATCH 1/3] Add sdk.Context and vm.EVM to precompiles Add context to precompiles: both Cosmos `sdk.Context` and `vm.EVM`. vm.EVM provides block, tx, along with state access. And if this PR https://github.com/ethereum/go-ethereum/pull/26119 is merged, it will also provide current call/subcall context. --- app/app.go | 9 ++++++++- x/evm/keeper/keeper.go | 28 ++++++++++++++-------------- x/evm/keeper/state_transition.go | 3 ++- x/evm/vm/geth/geth.go | 32 +++++++++++++++++++++++++------- x/evm/vm/interface.go | 5 ++++- 5 files changed, 53 insertions(+), 24 deletions(-) diff --git a/app/app.go b/app/app.go index a4dd4cd1c0..b15c1d910b 100644 --- a/app/app.go +++ b/app/app.go @@ -106,12 +106,15 @@ import ( "github.com/evmos/ethermint/x/evm" evmkeeper "github.com/evmos/ethermint/x/evm/keeper" evmtypes "github.com/evmos/ethermint/x/evm/types" + ethermintvm "github.com/evmos/ethermint/x/evm/vm" "github.com/evmos/ethermint/x/evm/vm/geth" "github.com/evmos/ethermint/x/feemarket" feemarketkeeper "github.com/evmos/ethermint/x/feemarket/keeper" feemarkettypes "github.com/evmos/ethermint/x/feemarket/types" // Force-load the tracer engines to trigger registration due to Go-Ethereum v1.10.15 changes + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/vm" _ "github.com/ethereum/go-ethereum/eth/tracers/js" _ "github.com/ethereum/go-ethereum/eth/tracers/native" ) @@ -397,7 +400,7 @@ func NewEthermintApp( app.EvmKeeper = evmkeeper.NewKeeper( appCodec, keys[evmtypes.StoreKey], tkeys[evmtypes.TransientKey], app.GetSubspace(evmtypes.ModuleName), app.AccountKeeper, app.BankKeeper, app.StakingKeeper, app.FeeMarketKeeper, - nil, geth.NewEVM, tracer, + app.ExtendPrecompiles, geth.NewEVM, tracer, ) // Create IBC Keeper @@ -809,6 +812,10 @@ func (app *EthermintApp) RegisterTendermintService(clientCtx client.Context) { ) } +func (app *EthermintApp) ExtendPrecompiles(ctx sdk.Context, evm *vm.EVM) ethermintvm.PrecompiledContracts { + return map[common.Address]vm.PrecompiledContract{} +} + // RegisterSwaggerAPI registers swagger route with API Server func RegisterSwaggerAPI(_ client.Context, rtr *mux.Router) { statikFS, err := fs.New() diff --git a/x/evm/keeper/keeper.go b/x/evm/keeper/keeper.go index 331082831d..0d428eb573 100644 --- a/x/evm/keeper/keeper.go +++ b/x/evm/keeper/keeper.go @@ -56,8 +56,8 @@ type Keeper struct { // EVM Hooks for tx post-processing hooks types.EvmHooks - // custom stateless precompiled smart contracts - customPrecompiles evm.PrecompiledContracts + // Precompile extensions + getPrecompilesExtended func(ctx sdk.Context, evm *vm.EVM) evm.PrecompiledContracts // evm constructor function evmConstructor evm.Constructor @@ -72,7 +72,7 @@ func NewKeeper( bankKeeper types.BankKeeper, sk types.StakingKeeper, fmk types.FeeMarketKeeper, - customPrecompiles evm.PrecompiledContracts, + pext func(ctx sdk.Context, evm *vm.EVM) evm.PrecompiledContracts, evmConstructor evm.Constructor, tracer string, ) *Keeper { @@ -88,17 +88,17 @@ 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, - paramSpace: paramSpace, - accountKeeper: ak, - bankKeeper: bankKeeper, - stakingKeeper: sk, - feeMarketKeeper: fmk, - storeKey: storeKey, - transientKey: transientKey, - customPrecompiles: customPrecompiles, - evmConstructor: evmConstructor, - tracer: tracer, + cdc: cdc, + paramSpace: paramSpace, + accountKeeper: ak, + bankKeeper: bankKeeper, + stakingKeeper: sk, + feeMarketKeeper: fmk, + storeKey: storeKey, + transientKey: transientKey, + getPrecompilesExtended: pext, + evmConstructor: evmConstructor, + tracer: tracer, } } diff --git a/x/evm/keeper/state_transition.go b/x/evm/keeper/state_transition.go index c3b225774f..bdf7626c08 100644 --- a/x/evm/keeper/state_transition.go +++ b/x/evm/keeper/state_transition.go @@ -96,7 +96,8 @@ 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) } // VMConfig creates an EVM configuration from the debug setting and the extra EIPs enabled on the diff --git a/x/evm/vm/geth/geth.go b/x/evm/vm/geth/geth.go index 259559cec4..c5b90abbde 100644 --- a/x/evm/vm/geth/geth.go +++ b/x/evm/vm/geth/geth.go @@ -3,6 +3,8 @@ package geth 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" @@ -18,22 +20,34 @@ var ( // EVM is the wrapper for the go-ethereum EVM. type EVM struct { *vm.EVM + precompiles evm.PrecompiledContracts } // NewEVM defines the constructor function for the go-ethereum (geth) EVM. It uses // 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) + customPrecompiles := getPrecompilesExtended(ctx, newEvm.EVM) + + for k, v := range customPrecompiles { + precompiles[k] = v + } + newEvm.precompiles = precompiles + + return newEvm } // Context returns the EVM's Block Context @@ -55,20 +69,24 @@ func (e EVM) Config() vm.Config { // 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] + p, found = e.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.ActivePrecompiles(rules) +func (e EVM) ActivePrecompiles(rules params.Rules) []common.Address { + // TODO e.precompiles + precompiles := vm.ActivePrecompiles(rules) + for key := range e.precompiles { + precompiles = append(precompiles, key) + } + return precompiles } // RunPrecompiledContract runs a stateless precompiled contract and ignores the address and // value arguments. It uses the RunPrecompiledContract function from the geth vm package. -func (EVM) RunPrecompiledContract( +func (e *EVM) RunPrecompiledContract( p evm.StatefulPrecompiledContract, _ common.Address, // address arg is unused input []byte, diff --git a/x/evm/vm/interface.go b/x/evm/vm/interface.go index d83a425406..43051e1e69 100644 --- a/x/evm/vm/interface.go +++ b/x/evm/vm/interface.go @@ -3,6 +3,8 @@ 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" @@ -57,10 +59,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 From b10130a1ea43268445ecbbf88841f8127aa2268e Mon Sep 17 00:00:00 2001 From: Loredana Cirstea Date: Sun, 6 Nov 2022 10:23:48 +0100 Subject: [PATCH 2/3] move go-ethereum imports above blank imports --- app/app.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/app.go b/app/app.go index b15c1d910b..e4cc75c79e 100644 --- a/app/app.go +++ b/app/app.go @@ -112,9 +112,10 @@ import ( feemarketkeeper "github.com/evmos/ethermint/x/feemarket/keeper" feemarkettypes "github.com/evmos/ethermint/x/feemarket/types" - // Force-load the tracer engines to trigger registration due to Go-Ethereum v1.10.15 changes "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/vm" + + // Force-load the tracer engines to trigger registration due to Go-Ethereum v1.10.15 changes _ "github.com/ethereum/go-ethereum/eth/tracers/js" _ "github.com/ethereum/go-ethereum/eth/tracers/native" ) From 4d620cd3e6871b859ad9a57c782f1c1a26b61e66 Mon Sep 17 00:00:00 2001 From: Loredana Cirstea Date: Sun, 6 Nov 2022 23:21:44 +0100 Subject: [PATCH 3/3] remove outdated todo --- x/evm/vm/geth/geth.go | 1 - 1 file changed, 1 deletion(-) diff --git a/x/evm/vm/geth/geth.go b/x/evm/vm/geth/geth.go index c5b90abbde..587e416642 100644 --- a/x/evm/vm/geth/geth.go +++ b/x/evm/vm/geth/geth.go @@ -76,7 +76,6 @@ func (e EVM) Precompile(addr common.Address) (p vm.PrecompiledContract, found bo // ActivePrecompiles returns a list of all the active precompiled contract addresses // for the current chain configuration. func (e EVM) ActivePrecompiles(rules params.Rules) []common.Address { - // TODO e.precompiles precompiles := vm.ActivePrecompiles(rules) for key := range e.precompiles { precompiles = append(precompiles, key)