From 1ddf4355517add1d90a8ac7459e647ee1df4efaa Mon Sep 17 00:00:00 2001 From: drklee3 Date: Mon, 8 Jan 2024 15:39:09 -0800 Subject: [PATCH 01/10] refactor(evm): Move StateDB types, use StateDB interface in keeper --- x/evm/genesis_test.go | 4 +- x/evm/handler_test.go | 5 ++- x/evm/keeper/config.go | 4 +- x/evm/keeper/grpc_query.go | 10 ++--- x/evm/keeper/grpc_query_test.go | 2 +- x/evm/keeper/hooks_test.go | 2 +- x/evm/keeper/keeper.go | 39 +++++++++-------- x/evm/keeper/keeper_test.go | 11 +++-- x/evm/keeper/msg_server_test.go | 4 +- x/evm/keeper/params_test.go | 4 ++ x/evm/keeper/state_transition.go | 6 +-- x/evm/keeper/state_transition_test.go | 5 ++- x/evm/keeper/statedb.go | 8 ++-- x/evm/keeper/statedb_test.go | 20 ++++----- x/evm/migrations/v3/store_test.go | 2 + x/evm/statedb/config.go | 29 ------------- x/evm/statedb/interfaces.go | 18 -------- x/evm/statedb/mock_test.go | 14 +++--- x/evm/statedb/state_object.go | 26 ++---------- x/evm/statedb/statedb.go | 12 +++--- x/evm/statedb/statedb_test.go | 44 ++++++++++--------- x/evm/types/statedb.go | 61 +++++++++++++++++++++++++++ x/evm/vm/interface.go | 44 +++++++++++++++++++ 23 files changed, 218 insertions(+), 156 deletions(-) create mode 100644 x/evm/types/statedb.go diff --git a/x/evm/genesis_test.go b/x/evm/genesis_test.go index e060c5d965..72262472e9 100644 --- a/x/evm/genesis_test.go +++ b/x/evm/genesis_test.go @@ -9,8 +9,8 @@ import ( "github.com/evmos/ethermint/crypto/ethsecp256k1" etherminttypes "github.com/evmos/ethermint/types" "github.com/evmos/ethermint/x/evm" - "github.com/evmos/ethermint/x/evm/statedb" "github.com/evmos/ethermint/x/evm/types" + "github.com/evmos/ethermint/x/evm/vm" ) func (suite *EvmTestSuite) TestInitGenesis() { @@ -19,7 +19,7 @@ func (suite *EvmTestSuite) TestInitGenesis() { address := common.HexToAddress(privkey.PubKey().Address().String()) - var vmdb *statedb.StateDB + var vmdb vm.StateDB testCases := []struct { name string diff --git a/x/evm/handler_test.go b/x/evm/handler_test.go index a554c6ee6a..68b2b74a1b 100644 --- a/x/evm/handler_test.go +++ b/x/evm/handler_test.go @@ -7,6 +7,7 @@ import ( "time" "github.com/evmos/ethermint/x/evm/keeper" + "github.com/evmos/ethermint/x/evm/vm" sdkmath "cosmossdk.io/math" "github.com/gogo/protobuf/proto" @@ -181,8 +182,8 @@ func (suite *EvmTestSuite) SignTx(tx *types.MsgEthereumTx) { suite.Require().NoError(err) } -func (suite *EvmTestSuite) StateDB() *statedb.StateDB { - return statedb.New(suite.ctx, suite.app.EvmKeeper, statedb.NewEmptyTxConfig(common.BytesToHash(suite.ctx.HeaderHash().Bytes()))) +func (suite *EvmTestSuite) StateDB() vm.StateDB { + return statedb.New(suite.ctx, suite.app.EvmKeeper, types.NewEmptyTxConfig(common.BytesToHash(suite.ctx.HeaderHash().Bytes()))) } func TestEvmTestSuite(t *testing.T) { diff --git a/x/evm/keeper/config.go b/x/evm/keeper/config.go index 3debb895de..1d76fd0d06 100644 --- a/x/evm/keeper/config.go +++ b/x/evm/keeper/config.go @@ -48,8 +48,8 @@ func (k *Keeper) EVMConfig(ctx sdk.Context, proposerAddress sdk.ConsAddress, cha } // TxConfig loads `TxConfig` from current transient storage -func (k *Keeper) TxConfig(ctx sdk.Context, txHash common.Hash) statedb.TxConfig { - return statedb.NewTxConfig( +func (k *Keeper) TxConfig(ctx sdk.Context, txHash common.Hash) types.TxConfig { + return types.NewTxConfig( common.BytesToHash(ctx.HeaderHash()), // BlockHash txHash, // TxHash uint(k.GetTxIndexTransient(ctx)), // TxIndex diff --git a/x/evm/keeper/grpc_query.go b/x/evm/keeper/grpc_query.go index 5e09153b59..f9d5b5e56f 100644 --- a/x/evm/keeper/grpc_query.go +++ b/x/evm/keeper/grpc_query.go @@ -255,7 +255,7 @@ func (k Keeper) EthCall(c context.Context, req *types.EthCallRequest) (*types.Ms return nil, status.Error(codes.InvalidArgument, err.Error()) } - txConfig := statedb.NewEmptyTxConfig(common.BytesToHash(ctx.HeaderHash())) + txConfig := types.NewEmptyTxConfig(common.BytesToHash(ctx.HeaderHash())) // pass false to not commit StateDB res, err := k.ApplyMessageWithConfig(ctx, msg, nil, false, cfg, txConfig) @@ -324,7 +324,7 @@ func (k Keeper) EstimateGas(c context.Context, req *types.EthCallRequest) (*type nonce := k.GetNonce(ctx, args.GetFrom()) args.Nonce = (*hexutil.Uint64)(&nonce) - txConfig := statedb.NewEmptyTxConfig(common.BytesToHash(ctx.HeaderHash().Bytes())) + txConfig := types.NewEmptyTxConfig(common.BytesToHash(ctx.HeaderHash().Bytes())) // convert the tx args to an ethereum message msg, err := args.ToMessage(req.GasCap, cfg.BaseFee) @@ -423,7 +423,7 @@ func (k Keeper) TraceTx(c context.Context, req *types.QueryTraceTxRequest) (*typ } signer := ethtypes.MakeSigner(cfg.ChainConfig, big.NewInt(ctx.BlockHeight())) - txConfig := statedb.NewEmptyTxConfig(common.BytesToHash(ctx.HeaderHash().Bytes())) + txConfig := types.NewEmptyTxConfig(common.BytesToHash(ctx.HeaderHash().Bytes())) for i, tx := range req.Predecessors { ethTx := tx.AsTransaction() msg, err := ethTx.AsMessage(signer, cfg.BaseFee) @@ -503,7 +503,7 @@ func (k Keeper) TraceBlock(c context.Context, req *types.QueryTraceBlockRequest) txsLength := len(req.Txs) results := make([]*types.TxTraceResult, 0, txsLength) - txConfig := statedb.NewEmptyTxConfig(common.BytesToHash(ctx.HeaderHash().Bytes())) + txConfig := types.NewEmptyTxConfig(common.BytesToHash(ctx.HeaderHash().Bytes())) for i, tx := range req.Txs { result := types.TxTraceResult{} ethTx := tx.AsTransaction() @@ -533,7 +533,7 @@ func (k Keeper) TraceBlock(c context.Context, req *types.QueryTraceBlockRequest) func (k *Keeper) traceTx( ctx sdk.Context, cfg *statedb.EVMConfig, - txConfig statedb.TxConfig, + txConfig types.TxConfig, signer ethtypes.Signer, tx *ethtypes.Transaction, traceConfig *types.TraceConfig, diff --git a/x/evm/keeper/grpc_query_test.go b/x/evm/keeper/grpc_query_test.go index 4149aa47f3..50849abf49 100644 --- a/x/evm/keeper/grpc_query_test.go +++ b/x/evm/keeper/grpc_query_test.go @@ -392,7 +392,7 @@ func (suite *KeeperTestSuite) TestQueryTxLogs() { suite.Run(fmt.Sprintf("Case %s", tc.msg), func() { suite.SetupTest() // reset - vmdb := statedb.New(suite.ctx, suite.app.EvmKeeper, statedb.NewTxConfig(common.BytesToHash(suite.ctx.HeaderHash().Bytes()), txHash, txIndex, logIndex)) + vmdb := statedb.New(suite.ctx, suite.app.EvmKeeper, types.NewTxConfig(common.BytesToHash(suite.ctx.HeaderHash().Bytes()), txHash, txIndex, logIndex)) tc.malleate(vmdb) suite.Require().NoError(vmdb.Commit()) diff --git a/x/evm/keeper/hooks_test.go b/x/evm/keeper/hooks_test.go index b635cf4cd4..27f6dc58a0 100644 --- a/x/evm/keeper/hooks_test.go +++ b/x/evm/keeper/hooks_test.go @@ -66,7 +66,7 @@ func (suite *KeeperTestSuite) TestEvmHooks() { k := suite.app.EvmKeeper ctx := suite.ctx txHash := common.BigToHash(big.NewInt(1)) - vmdb := statedb.New(ctx, k, statedb.NewTxConfig( + vmdb := statedb.New(ctx, k, types.NewTxConfig( common.BytesToHash(ctx.HeaderHash().Bytes()), txHash, 0, diff --git a/x/evm/keeper/keeper.go b/x/evm/keeper/keeper.go index 9c47491d8d..45e804dbfe 100644 --- a/x/evm/keeper/keeper.go +++ b/x/evm/keeper/keeper.go @@ -32,7 +32,6 @@ import ( "github.com/tendermint/tendermint/libs/log" ethermint "github.com/evmos/ethermint/types" - "github.com/evmos/ethermint/x/evm/statedb" "github.com/evmos/ethermint/x/evm/types" legacytypes "github.com/evmos/ethermint/x/evm/types/legacy" evm "github.com/evmos/ethermint/x/evm/vm" @@ -77,6 +76,10 @@ type Keeper struct { // evm constructor function evmConstructor evm.Constructor + + // stateDB constructor function + stateDBConstructor evm.StateDBConstructor + // Legacy subspace ss paramstypes.Subspace } @@ -92,6 +95,7 @@ func NewKeeper( fmk types.FeeMarketKeeper, customPrecompiles evm.PrecompiledContracts, evmConstructor evm.Constructor, + stateDBConstructor evm.StateDBConstructor, tracer string, ss paramstypes.Subspace, ) *Keeper { @@ -111,18 +115,19 @@ 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, + customPrecompiles: customPrecompiles, + evmConstructor: evmConstructor, + stateDBConstructor: stateDBConstructor, + tracer: tracer, + ss: ss, } } @@ -279,7 +284,7 @@ func (k Keeper) Tracer(ctx sdk.Context, msg core.Message, ethCfg *params.ChainCo // GetAccountWithoutBalance load nonce and codehash without balance, // more efficient in cases where balance is not needed. -func (k *Keeper) GetAccountWithoutBalance(ctx sdk.Context, addr common.Address) *statedb.Account { +func (k *Keeper) GetAccountWithoutBalance(ctx sdk.Context, addr common.Address) *types.StateDBAccount { cosmosAddr := sdk.AccAddress(addr.Bytes()) acct := k.accountKeeper.GetAccount(ctx, cosmosAddr) if acct == nil { @@ -292,21 +297,21 @@ func (k *Keeper) GetAccountWithoutBalance(ctx sdk.Context, addr common.Address) codeHash = ethAcct.GetCodeHash().Bytes() } - return &statedb.Account{ + return &types.StateDBAccount{ Nonce: acct.GetSequence(), CodeHash: codeHash, } } // GetAccountOrEmpty returns empty account if not exist, returns error if it's not `EthAccount` -func (k *Keeper) GetAccountOrEmpty(ctx sdk.Context, addr common.Address) statedb.Account { +func (k *Keeper) GetAccountOrEmpty(ctx sdk.Context, addr common.Address) types.StateDBAccount { acct := k.GetAccount(ctx, addr) if acct != nil { return *acct } // empty account - return statedb.Account{ + return types.StateDBAccount{ Balance: new(big.Int), CodeHash: types.EmptyCodeHash, } diff --git a/x/evm/keeper/keeper_test.go b/x/evm/keeper/keeper_test.go index 1b89527735..826a8f53cc 100644 --- a/x/evm/keeper/keeper_test.go +++ b/x/evm/keeper/keeper_test.go @@ -37,6 +37,7 @@ import ( "github.com/evmos/ethermint/x/evm/statedb" "github.com/evmos/ethermint/x/evm/types" evmtypes "github.com/evmos/ethermint/x/evm/types" + "github.com/evmos/ethermint/x/evm/vm" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" @@ -252,8 +253,12 @@ func (suite *KeeperTestSuite) Commit() { suite.queryClient = types.NewQueryClient(queryHelper) } -func (suite *KeeperTestSuite) StateDB() *statedb.StateDB { - return statedb.New(suite.ctx, suite.app.EvmKeeper, statedb.NewEmptyTxConfig(common.BytesToHash(suite.ctx.HeaderHash().Bytes()))) +func (suite *KeeperTestSuite) StateDB() vm.StateDB { + return statedb.New( + suite.ctx, + suite.app.EvmKeeper, + types.NewEmptyTxConfig(common.BytesToHash(suite.ctx.HeaderHash().Bytes())), + ) } // DeployTestContract deploy a test erc20 contract and returns the contract address @@ -498,7 +503,7 @@ func (suite *KeeperTestSuite) TestGetAccountStorage() { } func (suite *KeeperTestSuite) TestGetAccountOrEmpty() { - empty := statedb.Account{ + empty := types.StateDBAccount{ Balance: new(big.Int), CodeHash: types.EmptyCodeHash, } diff --git a/x/evm/keeper/msg_server_test.go b/x/evm/keeper/msg_server_test.go index 4a8c86cefa..39e4ae5383 100644 --- a/x/evm/keeper/msg_server_test.go +++ b/x/evm/keeper/msg_server_test.go @@ -8,8 +8,8 @@ import ( ethtypes "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/params" - "github.com/evmos/ethermint/x/evm/statedb" "github.com/evmos/ethermint/x/evm/types" + "github.com/evmos/ethermint/x/evm/vm" ) func (suite *KeeperTestSuite) TestEthereumTx() { @@ -17,7 +17,7 @@ func (suite *KeeperTestSuite) TestEthereumTx() { err error msg *types.MsgEthereumTx signer ethtypes.Signer - vmdb *statedb.StateDB + vmdb vm.StateDB chainCfg *params.ChainConfig expectedGasUsed uint64 ) diff --git a/x/evm/keeper/params_test.go b/x/evm/keeper/params_test.go index af64009aab..56b7e7b9b0 100644 --- a/x/evm/keeper/params_test.go +++ b/x/evm/keeper/params_test.go @@ -11,6 +11,7 @@ import ( "github.com/evmos/ethermint/app" "github.com/evmos/ethermint/encoding" "github.com/evmos/ethermint/x/evm/keeper" + "github.com/evmos/ethermint/x/evm/statedb" "github.com/evmos/ethermint/x/evm/types" legacytypes "github.com/evmos/ethermint/x/evm/types/legacy" legacytestutil "github.com/evmos/ethermint/x/evm/types/legacy/testutil" @@ -152,6 +153,7 @@ func (suite *KeeperTestSuite) TestLegacyParamsKeyTableRegistration() { ak, nil, nil, nil, nil, // OK to pass nil in for these since we only instantiate and use params geth.NewEVM, + statedb.New, "", unregisteredSubspace, ) @@ -209,6 +211,7 @@ func (suite *KeeperTestSuite) TestRenamedFieldReturnsProperValueForLegacyParams( ak, nil, nil, nil, nil, geth.NewEVM, + statedb.New, "", subspace, ) @@ -241,6 +244,7 @@ func (suite *KeeperTestSuite) TestNilLegacyParamsDoNotPanic() { ak, nil, nil, nil, nil, // OK to pass nil in for these since we only instantiate and use params geth.NewEVM, + statedb.New, "", subspace, ) diff --git a/x/evm/keeper/state_transition.go b/x/evm/keeper/state_transition.go index ad90dba5fd..ef02cdc3c3 100644 --- a/x/evm/keeper/state_transition.go +++ b/x/evm/keeper/state_transition.go @@ -268,7 +268,7 @@ func (k *Keeper) ApplyMessage(ctx sdk.Context, msg core.Message, tracer vm.EVMLo return nil, errorsmod.Wrap(err, "failed to load evm config") } - txConfig := statedb.NewEmptyTxConfig(common.BytesToHash(ctx.HeaderHash())) + txConfig := types.NewEmptyTxConfig(common.BytesToHash(ctx.HeaderHash())) return k.ApplyMessageWithConfig(ctx, msg, tracer, commit, cfg, txConfig) } @@ -315,7 +315,7 @@ func (k *Keeper) ApplyMessageWithConfig(ctx sdk.Context, tracer vm.EVMLogger, commit bool, cfg *statedb.EVMConfig, - txConfig statedb.TxConfig, + txConfig types.TxConfig, ) (*types.MsgEthereumTxResponse, error) { var ( ret []byte // return bytes from evm execution @@ -329,7 +329,7 @@ func (k *Keeper) ApplyMessageWithConfig(ctx sdk.Context, return nil, errorsmod.Wrap(types.ErrCallDisabled, "failed to call contract") } - stateDB := statedb.New(ctx, k, txConfig) + stateDB := k.stateDBConstructor(ctx, k, txConfig) evm := k.NewEVM(ctx, msg, cfg, tracer, stateDB) leftoverGas := msg.Gas() diff --git a/x/evm/keeper/state_transition_test.go b/x/evm/keeper/state_transition_test.go index b74f681d6b..f1fba5f00c 100644 --- a/x/evm/keeper/state_transition_test.go +++ b/x/evm/keeper/state_transition_test.go @@ -11,6 +11,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core" ethtypes "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/params" "github.com/evmos/ethermint/tests" "github.com/evmos/ethermint/x/evm/keeper" @@ -574,8 +575,8 @@ func (suite *KeeperTestSuite) TestApplyMessageWithConfig() { config *statedb.EVMConfig keeperParams types.Params signer ethtypes.Signer - vmdb *statedb.StateDB - txConfig statedb.TxConfig + vmdb vm.StateDB + txConfig types.TxConfig chainCfg *params.ChainConfig ) diff --git a/x/evm/keeper/statedb.go b/x/evm/keeper/statedb.go index c2cd893c5e..7644798354 100644 --- a/x/evm/keeper/statedb.go +++ b/x/evm/keeper/statedb.go @@ -27,18 +27,18 @@ import ( authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" "github.com/ethereum/go-ethereum/common" ethermint "github.com/evmos/ethermint/types" - "github.com/evmos/ethermint/x/evm/statedb" "github.com/evmos/ethermint/x/evm/types" + "github.com/evmos/ethermint/x/evm/vm" ) -var _ statedb.Keeper = &Keeper{} +var _ vm.StateDBKeeper = &Keeper{} // ---------------------------------------------------------------------------- // StateDB Keeper implementation // ---------------------------------------------------------------------------- // GetAccount returns nil if account is not exist, returns error if it's not `EthAccountI` -func (k *Keeper) GetAccount(ctx sdk.Context, addr common.Address) *statedb.Account { +func (k *Keeper) GetAccount(ctx sdk.Context, addr common.Address) *types.StateDBAccount { acct := k.GetAccountWithoutBalance(ctx, addr) if acct == nil { return nil @@ -119,7 +119,7 @@ func (k *Keeper) SetBalance(ctx sdk.Context, addr common.Address, amount *big.In } // SetAccount updates nonce/balance/codeHash together. -func (k *Keeper) SetAccount(ctx sdk.Context, addr common.Address, account statedb.Account) error { +func (k *Keeper) SetAccount(ctx sdk.Context, addr common.Address, account types.StateDBAccount) error { // update account cosmosAddr := sdk.AccAddress(addr.Bytes()) acct := k.accountKeeper.GetAccount(ctx, cosmosAddr) diff --git a/x/evm/keeper/statedb_test.go b/x/evm/keeper/statedb_test.go index fecb8392f5..af60a73d9c 100644 --- a/x/evm/keeper/statedb_test.go +++ b/x/evm/keeper/statedb_test.go @@ -233,55 +233,55 @@ func (suite *KeeperTestSuite) TestSetAccount() { testCases := []struct { name string address common.Address - account statedb.Account + account types.StateDBAccount expectedErr error }{ { "new account, non-contract account", tests.GenerateAddress(), - statedb.Account{10, big.NewInt(100), types.EmptyCodeHash}, + types.StateDBAccount{10, big.NewInt(100), types.EmptyCodeHash}, nil, }, { "new account, contract account", tests.GenerateAddress(), - statedb.Account{10, big.NewInt(100), crypto.Keccak256Hash([]byte("some code hash")).Bytes()}, + types.StateDBAccount{10, big.NewInt(100), crypto.Keccak256Hash([]byte("some code hash")).Bytes()}, nil, }, { "existing eth account, non-contract account", ethAddr, - statedb.Account{10, big.NewInt(1), types.EmptyCodeHash}, + types.StateDBAccount{10, big.NewInt(1), types.EmptyCodeHash}, nil, }, { "existing eth account, contract account", ethAddr, - statedb.Account{10, big.NewInt(0), crypto.Keccak256Hash([]byte("some code hash")).Bytes()}, + types.StateDBAccount{10, big.NewInt(0), crypto.Keccak256Hash([]byte("some code hash")).Bytes()}, nil, }, { "existing base account, non-contract account", baseAddr, - statedb.Account{10, big.NewInt(10), types.EmptyCodeHash}, + types.StateDBAccount{10, big.NewInt(10), types.EmptyCodeHash}, nil, }, { "existing base account, contract account", baseAddr, - statedb.Account{10, big.NewInt(99), crypto.Keccak256Hash([]byte("some code hash")).Bytes()}, + types.StateDBAccount{10, big.NewInt(99), crypto.Keccak256Hash([]byte("some code hash")).Bytes()}, nil, }, { "existing vesting account, non-contract account", vestingAddr, - statedb.Account{10, big.NewInt(1000), types.EmptyCodeHash}, + types.StateDBAccount{10, big.NewInt(1000), types.EmptyCodeHash}, nil, }, { "existing vesting account, contract account", vestingAddr, - statedb.Account{10, big.NewInt(1001), crypto.Keccak256Hash([]byte("some code hash")).Bytes()}, + types.StateDBAccount{10, big.NewInt(1001), crypto.Keccak256Hash([]byte("some code hash")).Bytes()}, types.ErrInvalidAccount, }, } @@ -791,7 +791,7 @@ func (suite *KeeperTestSuite) TestAddLog() { for _, tc := range testCases { suite.Run(tc.name, func() { suite.SetupTest() - vmdb := statedb.New(suite.ctx, suite.app.EvmKeeper, statedb.NewTxConfig( + vmdb := statedb.New(suite.ctx, suite.app.EvmKeeper, types.NewTxConfig( common.BytesToHash(suite.ctx.HeaderHash().Bytes()), tc.hash, 0, 0, diff --git a/x/evm/migrations/v3/store_test.go b/x/evm/migrations/v3/store_test.go index a01916a6f7..12ff79409a 100644 --- a/x/evm/migrations/v3/store_test.go +++ b/x/evm/migrations/v3/store_test.go @@ -4,6 +4,7 @@ import ( "testing" "github.com/evmos/ethermint/x/evm/keeper" + "github.com/evmos/ethermint/x/evm/statedb" "github.com/evmos/ethermint/x/evm/types" "github.com/evmos/ethermint/x/evm/vm/geth" "github.com/stretchr/testify/require" @@ -151,6 +152,7 @@ func TestKeyTableCompatiabilityWithKeeper(t *testing.T) { ak, nil, nil, nil, nil, geth.NewEVM, + statedb.New, "", subspace, ) diff --git a/x/evm/statedb/config.go b/x/evm/statedb/config.go index d9baa5387f..445ae0d47c 100644 --- a/x/evm/statedb/config.go +++ b/x/evm/statedb/config.go @@ -23,35 +23,6 @@ import ( "github.com/evmos/ethermint/x/evm/types" ) -// TxConfig encapulates the readonly information of current tx for `StateDB`. -type TxConfig struct { - BlockHash common.Hash // hash of current block - TxHash common.Hash // hash of current tx - TxIndex uint // the index of current transaction - LogIndex uint // the index of next log within current block -} - -// NewTxConfig returns a TxConfig -func NewTxConfig(bhash, thash common.Hash, txIndex, logIndex uint) TxConfig { - return TxConfig{ - BlockHash: bhash, - TxHash: thash, - TxIndex: txIndex, - LogIndex: logIndex, - } -} - -// NewEmptyTxConfig construct an empty TxConfig, -// used in context where there's no transaction, e.g. `eth_call`/`eth_estimateGas`. -func NewEmptyTxConfig(bhash common.Hash) TxConfig { - return TxConfig{ - BlockHash: bhash, - TxHash: common.Hash{}, - TxIndex: 0, - LogIndex: 0, - } -} - // EVMConfig encapsulates common parameters needed to create an EVM to execute a message // It's mainly to reduce the number of method parameters type EVMConfig struct { diff --git a/x/evm/statedb/interfaces.go b/x/evm/statedb/interfaces.go index e4e83e09c3..eb8494d719 100644 --- a/x/evm/statedb/interfaces.go +++ b/x/evm/statedb/interfaces.go @@ -16,8 +16,6 @@ package statedb import ( - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/vm" ) @@ -30,19 +28,3 @@ type ExtStateDB interface { vm.StateDB AppendJournalEntry(JournalEntry) } - -// Keeper provide underlying storage of StateDB -type Keeper interface { - // Read methods - GetAccount(ctx sdk.Context, addr common.Address) *Account - GetState(ctx sdk.Context, addr common.Address, key common.Hash) common.Hash - GetCode(ctx sdk.Context, codeHash common.Hash) []byte - // the callback returns false to break early - ForEachStorage(ctx sdk.Context, addr common.Address, cb func(key, value common.Hash) bool) - - // Write methods, only called by `StateDB.Commit()` - SetAccount(ctx sdk.Context, addr common.Address, account Account) error - SetState(ctx sdk.Context, addr common.Address, key common.Hash, value []byte) - SetCode(ctx sdk.Context, codeHash []byte, code []byte) - DeleteAccount(ctx sdk.Context, addr common.Address) error -} diff --git a/x/evm/statedb/mock_test.go b/x/evm/statedb/mock_test.go index 544cbfa1b4..88c270ed5e 100644 --- a/x/evm/statedb/mock_test.go +++ b/x/evm/statedb/mock_test.go @@ -9,16 +9,18 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" "github.com/evmos/ethermint/x/evm/statedb" + "github.com/evmos/ethermint/x/evm/types" + "github.com/evmos/ethermint/x/evm/vm" ) var ( - _ statedb.Keeper = &MockKeeper{} - errAddress common.Address = common.BigToAddress(big.NewInt(100)) - emptyCodeHash = crypto.Keccak256(nil) + _ vm.StateDBKeeper = &MockKeeper{} + errAddress common.Address = common.BigToAddress(big.NewInt(100)) + emptyCodeHash = crypto.Keccak256(nil) ) type MockAcount struct { - account statedb.Account + account types.StateDBAccount states statedb.Storage } @@ -34,7 +36,7 @@ func NewMockKeeper() *MockKeeper { } } -func (k MockKeeper) GetAccount(ctx sdk.Context, addr common.Address) *statedb.Account { +func (k MockKeeper) GetAccount(ctx sdk.Context, addr common.Address) *types.StateDBAccount { acct, ok := k.accounts[addr] if !ok { return nil @@ -60,7 +62,7 @@ func (k MockKeeper) ForEachStorage(ctx sdk.Context, addr common.Address, cb func } } -func (k MockKeeper) SetAccount(ctx sdk.Context, addr common.Address, account statedb.Account) error { +func (k MockKeeper) SetAccount(ctx sdk.Context, addr common.Address, account types.StateDBAccount) error { if addr == errAddress { return errors.New("mock db error") } diff --git a/x/evm/statedb/state_object.go b/x/evm/statedb/state_object.go index dd344dfadb..485e836191 100644 --- a/x/evm/statedb/state_object.go +++ b/x/evm/statedb/state_object.go @@ -22,31 +22,11 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" + "github.com/evmos/ethermint/x/evm/types" ) var emptyCodeHash = crypto.Keccak256(nil) -// Account is the Ethereum consensus representation of accounts. -// These objects are stored in the storage of auth module. -type Account struct { - Nonce uint64 - Balance *big.Int - CodeHash []byte -} - -// NewEmptyAccount returns an empty account. -func NewEmptyAccount() *Account { - return &Account{ - Balance: new(big.Int), - CodeHash: emptyCodeHash, - } -} - -// IsContract returns if the account contains contract code. -func (acct Account) IsContract() bool { - return !bytes.Equal(acct.CodeHash, emptyCodeHash) -} - // Storage represents in-memory cache/buffer of contract storage. type Storage map[common.Hash]common.Hash @@ -68,7 +48,7 @@ func (s Storage) SortedKeys() []common.Hash { type stateObject struct { db *StateDB - account Account + account types.StateDBAccount code []byte // state storage @@ -83,7 +63,7 @@ type stateObject struct { } // newObject creates a state object. -func newObject(db *StateDB, address common.Address, account Account) *stateObject { +func newObject(db *StateDB, address common.Address, account types.StateDBAccount) *stateObject { if account.Balance == nil { account.Balance = new(big.Int) } diff --git a/x/evm/statedb/statedb.go b/x/evm/statedb/statedb.go index 941cb0c21b..5a254efc18 100644 --- a/x/evm/statedb/statedb.go +++ b/x/evm/statedb/statedb.go @@ -26,6 +26,8 @@ import ( ethtypes "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" + "github.com/evmos/ethermint/x/evm/types" + evm "github.com/evmos/ethermint/x/evm/vm" ) // revision is the identifier of a version of state. @@ -44,7 +46,7 @@ var _ vm.StateDB = &StateDB{} // * Contracts // * Accounts type StateDB struct { - keeper Keeper + keeper evm.StateDBKeeper ctx sdk.Context // Journal of state modifications. This is the backbone of @@ -55,7 +57,7 @@ type StateDB struct { stateObjects map[common.Address]*stateObject - txConfig TxConfig + txConfig types.TxConfig // The refund counter, also used by state transitioning. refund uint64 @@ -68,7 +70,7 @@ type StateDB struct { } // New creates a new state from a given trie. -func New(ctx sdk.Context, keeper Keeper, txConfig TxConfig) *StateDB { +func New(ctx sdk.Context, keeper evm.StateDBKeeper, txConfig types.TxConfig) evm.StateDB { return &StateDB{ keeper: keeper, ctx: ctx, @@ -81,7 +83,7 @@ func New(ctx sdk.Context, keeper Keeper, txConfig TxConfig) *StateDB { } // Keeper returns the underlying `Keeper` -func (s *StateDB) Keeper() Keeper { +func (s *StateDB) Keeper() evm.StateDBKeeper { return s.keeper } @@ -246,7 +248,7 @@ func (s *StateDB) getOrNewStateObject(addr common.Address) *stateObject { func (s *StateDB) createObject(addr common.Address) (newobj, prev *stateObject) { prev = s.getStateObject(addr) - newobj = newObject(s, addr, Account{}) + newobj = newObject(s, addr, types.StateDBAccount{}) if prev == nil { s.journal.append(createObjectChange{account: &addr}) } else { diff --git a/x/evm/statedb/statedb_test.go b/x/evm/statedb/statedb_test.go index 3a491aa8cc..cac980e92e 100644 --- a/x/evm/statedb/statedb_test.go +++ b/x/evm/statedb/statedb_test.go @@ -10,15 +10,17 @@ import ( "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" "github.com/evmos/ethermint/x/evm/statedb" + "github.com/evmos/ethermint/x/evm/types" + evm "github.com/evmos/ethermint/x/evm/vm" "github.com/stretchr/testify/suite" ) var ( - address common.Address = common.BigToAddress(big.NewInt(101)) - address2 common.Address = common.BigToAddress(big.NewInt(102)) - address3 common.Address = common.BigToAddress(big.NewInt(103)) - blockHash common.Hash = common.BigToHash(big.NewInt(9999)) - emptyTxConfig statedb.TxConfig = statedb.NewEmptyTxConfig(blockHash) + address common.Address = common.BigToAddress(big.NewInt(101)) + address2 common.Address = common.BigToAddress(big.NewInt(102)) + address3 common.Address = common.BigToAddress(big.NewInt(103)) + blockHash common.Hash = common.BigToHash(big.NewInt(9999)) + emptyTxConfig types.TxConfig = types.NewEmptyTxConfig(blockHash) ) type StateDBTestSuite struct { @@ -32,9 +34,9 @@ func (suite *StateDBTestSuite) TestAccount() { value2 := common.BigToHash(big.NewInt(4)) testCases := []struct { name string - malleate func(*statedb.StateDB) + malleate func(evm.StateDB) }{ - {"non-exist account", func(db *statedb.StateDB) { + {"non-exist account", func(db evm.StateDB) { suite.Require().Equal(false, db.Exist(address)) suite.Require().Equal(true, db.Empty(address)) suite.Require().Equal(big.NewInt(0), db.GetBalance(address)) @@ -42,13 +44,13 @@ func (suite *StateDBTestSuite) TestAccount() { suite.Require().Equal(common.Hash{}, db.GetCodeHash(address)) suite.Require().Equal(uint64(0), db.GetNonce(address)) }}, - {"empty account", func(db *statedb.StateDB) { + {"empty account", func(db evm.StateDB) { db.CreateAccount(address) suite.Require().NoError(db.Commit()) keeper := db.Keeper().(*MockKeeper) acct := keeper.accounts[address] - suite.Require().Equal(statedb.NewEmptyAccount(), &acct.account) + suite.Require().Equal(types.NewEmptyAccount(), &acct.account) suite.Require().Empty(acct.states) suite.Require().False(acct.account.IsContract()) @@ -60,7 +62,7 @@ func (suite *StateDBTestSuite) TestAccount() { suite.Require().Equal(common.BytesToHash(emptyCodeHash), db.GetCodeHash(address)) suite.Require().Equal(uint64(0), db.GetNonce(address)) }}, - {"suicide", func(db *statedb.StateDB) { + {"suicide", func(db evm.StateDB) { // non-exist account. suite.Require().False(db.Suicide(address)) suite.Require().False(db.HasSuicided(address)) @@ -150,22 +152,22 @@ func (suite *StateDBTestSuite) TestBalance() { // NOTE: no need to test overflow/underflow, that is guaranteed by evm implementation. testCases := []struct { name string - malleate func(*statedb.StateDB) + malleate func(evm.StateDB) expBalance *big.Int }{ - {"add balance", func(db *statedb.StateDB) { + {"add balance", func(db evm.StateDB) { db.AddBalance(address, big.NewInt(10)) }, big.NewInt(10)}, - {"sub balance", func(db *statedb.StateDB) { + {"sub balance", func(db evm.StateDB) { db.AddBalance(address, big.NewInt(10)) // get dirty balance suite.Require().Equal(big.NewInt(10), db.GetBalance(address)) db.SubBalance(address, big.NewInt(2)) }, big.NewInt(8)}, - {"add zero balance", func(db *statedb.StateDB) { + {"add zero balance", func(db evm.StateDB) { db.AddBalance(address, big.NewInt(0)) }, big.NewInt(0)}, - {"sub zero balance", func(db *statedb.StateDB) { + {"sub zero balance", func(db evm.StateDB) { db.SubBalance(address, big.NewInt(0)) }, big.NewInt(0)}, } @@ -190,19 +192,19 @@ func (suite *StateDBTestSuite) TestState() { value1 := common.BigToHash(big.NewInt(1)) testCases := []struct { name string - malleate func(*statedb.StateDB) + malleate func(evm.StateDB) expStates statedb.Storage }{ - {"empty state", func(db *statedb.StateDB) { + {"empty state", func(db evm.StateDB) { }, nil}, - {"set empty value", func(db *statedb.StateDB) { + {"set empty value", func(db evm.StateDB) { db.SetState(address, key1, common.Hash{}) }, statedb.Storage{}}, - {"noop state change", func(db *statedb.StateDB) { + {"noop state change", func(db evm.StateDB) { db.SetState(address, key1, value1) db.SetState(address, key1, common.Hash{}) }, statedb.Storage{}}, - {"set state", func(db *statedb.StateDB) { + {"set state", func(db evm.StateDB) { // check empty initial state suite.Require().Equal(common.Hash{}, db.GetState(address, key1)) suite.Require().Equal(common.Hash{}, db.GetCommittedState(address, key1)) @@ -466,7 +468,7 @@ func (suite *StateDBTestSuite) TestAccessList() { func (suite *StateDBTestSuite) TestLog() { txHash := common.BytesToHash([]byte("tx")) // use a non-default tx config - txConfig := statedb.NewTxConfig( + txConfig := types.NewTxConfig( blockHash, txHash, 1, 1, diff --git a/x/evm/types/statedb.go b/x/evm/types/statedb.go new file mode 100644 index 0000000000..866cfd3441 --- /dev/null +++ b/x/evm/types/statedb.go @@ -0,0 +1,61 @@ +package types + +import ( + "bytes" + "math/big" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" +) + +var emptyCodeHash = crypto.Keccak256(nil) + +// StateDBAccount is the Ethereum consensus representation of accounts. +// These objects are stored in the storage of auth module. +type StateDBAccount struct { + Nonce uint64 + Balance *big.Int + CodeHash []byte +} + +// NewEmptyAccount returns an empty account. +func NewEmptyAccount() *StateDBAccount { + return &StateDBAccount{ + Balance: new(big.Int), + CodeHash: emptyCodeHash, + } +} + +// IsContract returns if the account contains contract code. +func (acct StateDBAccount) IsContract() bool { + return !bytes.Equal(acct.CodeHash, emptyCodeHash) +} + +// TxConfig encapulates the readonly information of current tx for `StateDB`. +type TxConfig struct { + BlockHash common.Hash // hash of current block + TxHash common.Hash // hash of current tx + TxIndex uint // the index of current transaction + LogIndex uint // the index of next log within current block +} + +// NewTxConfig returns a TxConfig +func NewTxConfig(bhash, thash common.Hash, txIndex, logIndex uint) TxConfig { + return TxConfig{ + BlockHash: bhash, + TxHash: thash, + TxIndex: txIndex, + LogIndex: logIndex, + } +} + +// NewEmptyTxConfig construct an empty TxConfig, +// used in context where there's no transaction, e.g. `eth_call`/`eth_estimateGas`. +func NewEmptyTxConfig(bhash common.Hash) TxConfig { + return TxConfig{ + BlockHash: bhash, + TxHash: common.Hash{}, + TxIndex: 0, + LogIndex: 0, + } +} diff --git a/x/evm/vm/interface.go b/x/evm/vm/interface.go index f1a6f4f707..9e5d05e6d4 100644 --- a/x/evm/vm/interface.go +++ b/x/evm/vm/interface.go @@ -18,7 +18,11 @@ package vm import ( "math/big" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/evmos/ethermint/x/evm/types" + "github.com/ethereum/go-ethereum/common" + ethtypes "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/params" "github.com/holiman/uint256" @@ -79,3 +83,43 @@ type Constructor func( config vm.Config, customPrecompiles PrecompiledContracts, ) EVM + +// StateDBKeeper provide underlying storage of StateDB +type StateDBKeeper interface { + // Read methods + GetAccount(ctx sdk.Context, addr common.Address) *types.StateDBAccount + GetState(ctx sdk.Context, addr common.Address, key common.Hash) common.Hash + GetCode(ctx sdk.Context, codeHash common.Hash) []byte + // the callback returns false to break early + ForEachStorage(ctx sdk.Context, addr common.Address, cb func(key, value common.Hash) bool) + + // Write methods, only called by `StateDB.Commit()` + SetAccount(ctx sdk.Context, addr common.Address, account types.StateDBAccount) error + SetState(ctx sdk.Context, addr common.Address, key common.Hash, value []byte) + SetCode(ctx sdk.Context, codeHash []byte, code []byte) + DeleteAccount(ctx sdk.Context, addr common.Address) error +} + +type StateDB interface { + vm.StateDB + + Keeper() StateDBKeeper + + // Additional methods required by x/evm Keeper + Commit() error + Logs() []*ethtypes.Log +} + +// TxConfig provides readonly information of current tx for `StateDB`. +type TxConfig interface { + BlockHash() common.Hash // hash of current block + TxHash() common.Hash // hash of current tx + TxIndex() uint // the index of current transaction + LogIndex() uint // the index of next log within current block +} + +type StateDBConstructor func( + ctx sdk.Context, + keeper StateDBKeeper, + txConfig types.TxConfig, +) StateDB From 8644185d9826dafae0c41a8500e4c2ea07ab2008 Mon Sep 17 00:00:00 2001 From: drklee3 Date: Mon, 8 Jan 2024 15:46:41 -0800 Subject: [PATCH 02/10] Update statedb usage in app --- app/ante/eth.go | 5 +++-- app/ante/eth_test.go | 8 ++++---- app/ante/interfaces.go | 2 +- app/ante/sigs_test.go | 4 ++-- app/ante/utils_test.go | 5 +++-- app/app.go | 3 ++- 6 files changed, 15 insertions(+), 12 deletions(-) diff --git a/app/ante/eth.go b/app/ante/eth.go index 2402167be7..90a1c45e54 100644 --- a/app/ante/eth.go +++ b/app/ante/eth.go @@ -28,6 +28,7 @@ import ( ethermint "github.com/evmos/ethermint/types" "github.com/evmos/ethermint/x/evm/keeper" "github.com/evmos/ethermint/x/evm/statedb" + "github.com/evmos/ethermint/x/evm/types" evmtypes "github.com/evmos/ethermint/x/evm/types" "github.com/ethereum/go-ethereum/common" @@ -88,7 +89,7 @@ func (avd EthAccountVerificationDecorator) AnteHandle( if acct == nil { acc := avd.ak.NewAccountWithAddress(ctx, from) avd.ak.SetAccount(ctx, acc) - acct = statedb.NewEmptyAccount() + acct = types.NewEmptyAccount() } else if acct.IsContract() { return ctx, errorsmod.Wrapf(errortypes.ErrInvalidType, "the sender is not EOA: address %s, codeHash <%s>", fromAddr, acct.CodeHash) @@ -302,7 +303,7 @@ func (ctd CanTransferDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate BaseFee: baseFee, } - stateDB := statedb.New(ctx, ctd.evmKeeper, statedb.NewEmptyTxConfig(common.BytesToHash(ctx.HeaderHash().Bytes()))) + stateDB := statedb.New(ctx, ctd.evmKeeper, types.NewEmptyTxConfig(common.BytesToHash(ctx.HeaderHash().Bytes()))) evm := ctd.evmKeeper.NewEVM(ctx, coreMsg, cfg, evmtypes.NewNoOpTracer(), stateDB) // check that caller has enough balance to cover asset transfer for **topmost** call diff --git a/app/ante/eth_test.go b/app/ante/eth_test.go index 0fb9ea8b20..b5dd9dd7f1 100644 --- a/app/ante/eth_test.go +++ b/app/ante/eth_test.go @@ -10,8 +10,8 @@ import ( "github.com/evmos/ethermint/server/config" "github.com/evmos/ethermint/tests" ethermint "github.com/evmos/ethermint/types" - "github.com/evmos/ethermint/x/evm/statedb" evmtypes "github.com/evmos/ethermint/x/evm/types" + "github.com/evmos/ethermint/x/evm/vm" ethtypes "github.com/ethereum/go-ethereum/core/types" ) @@ -26,7 +26,7 @@ func (suite AnteTestSuite) TestNewEthAccountVerificationDecorator() { tx := evmtypes.NewTxContract(suite.app.EvmKeeper.ChainID(), 1, big.NewInt(10), 1000, big.NewInt(1), nil, nil, nil, nil) tx.From = addr.Hex() - var vmdb *statedb.StateDB + var vmdb vm.StateDB testCases := []struct { name string @@ -192,7 +192,7 @@ func (suite AnteTestSuite) TestEthGasConsumeDecorator() { dynamicFeeTx.From = addr.Hex() dynamicFeeTxPriority := int64(1) - var vmdb *statedb.StateDB + var vmdb vm.StateDB testCases := []struct { name string @@ -352,7 +352,7 @@ func (suite AnteTestSuite) TestCanTransferDecorator() { err := tx.Sign(suite.ethSigner, tests.NewSigner(privKey)) suite.Require().NoError(err) - var vmdb *statedb.StateDB + var vmdb vm.StateDB testCases := []struct { name string diff --git a/app/ante/interfaces.go b/app/ante/interfaces.go index e48e0a50a4..c2bb63cd62 100644 --- a/app/ante/interfaces.go +++ b/app/ante/interfaces.go @@ -41,7 +41,7 @@ type DynamicFeeEVMKeeper interface { // EVMKeeper defines the expected keeper interface used on the Eth AnteHandler type EVMKeeper interface { - statedb.Keeper + evm.StateDBKeeper DynamicFeeEVMKeeper NewEVM(ctx sdk.Context, msg core.Message, cfg *statedb.EVMConfig, tracer vm.EVMLogger, stateDB vm.StateDB) evm.EVM diff --git a/app/ante/sigs_test.go b/app/ante/sigs_test.go index 0c7b0539c8..be87ab15f3 100644 --- a/app/ante/sigs_test.go +++ b/app/ante/sigs_test.go @@ -4,7 +4,7 @@ import ( "math/big" "github.com/evmos/ethermint/tests" - "github.com/evmos/ethermint/x/evm/statedb" + "github.com/evmos/ethermint/x/evm/types" evmtypes "github.com/evmos/ethermint/x/evm/types" ) @@ -15,7 +15,7 @@ func (suite AnteTestSuite) TestSignatures() { addr, privKey := tests.NewAddrKey() to := tests.GenerateAddress() - acc := statedb.NewEmptyAccount() + acc := types.NewEmptyAccount() acc.Nonce = 1 acc.Balance = big.NewInt(10000000000) diff --git a/app/ante/utils_test.go b/app/ante/utils_test.go index c92961c391..e87c82e839 100644 --- a/app/ante/utils_test.go +++ b/app/ante/utils_test.go @@ -53,6 +53,7 @@ import ( "github.com/evmos/ethermint/tests" "github.com/evmos/ethermint/x/evm/statedb" evmtypes "github.com/evmos/ethermint/x/evm/types" + "github.com/evmos/ethermint/x/evm/vm" feemarkettypes "github.com/evmos/ethermint/x/feemarket/types" tmproto "github.com/tendermint/tendermint/proto/tendermint/types" @@ -73,8 +74,8 @@ type AnteTestSuite struct { const TestGasLimit uint64 = 100000 -func (suite *AnteTestSuite) StateDB() *statedb.StateDB { - return statedb.New(suite.ctx, suite.app.EvmKeeper, statedb.NewEmptyTxConfig(common.BytesToHash(suite.ctx.HeaderHash().Bytes()))) +func (suite *AnteTestSuite) StateDB() vm.StateDB { + return statedb.New(suite.ctx, suite.app.EvmKeeper, evmtypes.NewEmptyTxConfig(common.BytesToHash(suite.ctx.HeaderHash().Bytes()))) } func (suite *AnteTestSuite) SetupTest() { diff --git a/app/app.go b/app/app.go index 7b5f98d319..7191014db5 100644 --- a/app/app.go +++ b/app/app.go @@ -123,6 +123,7 @@ import ( ethermint "github.com/evmos/ethermint/types" "github.com/evmos/ethermint/x/evm" evmkeeper "github.com/evmos/ethermint/x/evm/keeper" + "github.com/evmos/ethermint/x/evm/statedb" evmtypes "github.com/evmos/ethermint/x/evm/types" legacyevmtypes "github.com/evmos/ethermint/x/evm/types/legacy" "github.com/evmos/ethermint/x/evm/vm/geth" @@ -422,7 +423,7 @@ func NewEthermintApp( appCodec, keys[evmtypes.StoreKey], tkeys[evmtypes.TransientKey], authtypes.NewModuleAddress(govtypes.ModuleName), app.AccountKeeper, app.BankKeeper, app.StakingKeeper, app.FeeMarketKeeper, - nil, geth.NewEVM, tracer, evmSs, + nil, geth.NewEVM, statedb.New, tracer, evmSs, ) // Create IBC Keeper From f18fd53909e929a63d31e98fb328b699087e0f91 Mon Sep 17 00:00:00 2001 From: drklee3 Date: Thu, 8 Feb 2024 13:28:25 -0800 Subject: [PATCH 03/10] fix: Resolve importer test Statedb types --- tests/importer/importer_test.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/importer/importer_test.go b/tests/importer/importer_test.go index a32a730206..04e8918e29 100644 --- a/tests/importer/importer_test.go +++ b/tests/importer/importer_test.go @@ -18,6 +18,8 @@ import ( evmkeeper "github.com/evmos/ethermint/x/evm/keeper" "github.com/evmos/ethermint/x/evm/statedb" + evmtypes "github.com/evmos/ethermint/x/evm/types" + "github.com/evmos/ethermint/x/evm/vm" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/consensus/ethash" @@ -140,7 +142,7 @@ func (suite *ImporterTestSuite) TestImportBlocks() { }) ctx := suite.app.NewContext(false, tmheader) ctx = ctx.WithBlockHeight(tmheader.Height) - vmdb := statedb.New(ctx, suite.app.EvmKeeper, statedb.NewEmptyTxConfig(common.BytesToHash(ctx.HeaderHash().Bytes()))) + vmdb := statedb.New(ctx, suite.app.EvmKeeper, evmtypes.NewEmptyTxConfig(common.BytesToHash(ctx.HeaderHash().Bytes()))) if chainConfig.DAOForkSupport && chainConfig.DAOForkBlock != nil && chainConfig.DAOForkBlock.Cmp(block.Number()) == 0 { applyDAOHardFork(vmdb) @@ -226,7 +228,7 @@ func applyDAOHardFork(vmdb ethvm.StateDB) { // Ref: https://github.com/ethereum/go-ethereum/blob/52f2461774bcb8cdd310f86b4bc501df5b783852/core/state_processor.go#L88 func applyTransaction( ctx sdk.Context, config *ethparams.ChainConfig, bc ethcore.ChainContext, author *common.Address, - gp *ethcore.GasPool, evmKeeper *evmkeeper.Keeper, vmdb *statedb.StateDB, header *ethtypes.Header, + gp *ethcore.GasPool, evmKeeper *evmkeeper.Keeper, vmdb vm.StateDB, header *ethtypes.Header, tx *ethtypes.Transaction, usedGas *uint64, cfg ethvm.Config, ) (*ethtypes.Receipt, uint64, error) { msg, err := tx.AsMessage(ethtypes.MakeSigner(config, header.Number), sdk.ZeroInt().BigInt()) From 19a0c79189033e8db6aec5f1b58ef669e517d68e Mon Sep 17 00:00:00 2001 From: drklee3 Date: Thu, 8 Feb 2024 13:30:12 -0800 Subject: [PATCH 04/10] Resolve multi import --- app/ante/eth.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/app/ante/eth.go b/app/ante/eth.go index 90a1c45e54..669afccf3c 100644 --- a/app/ante/eth.go +++ b/app/ante/eth.go @@ -28,7 +28,6 @@ import ( ethermint "github.com/evmos/ethermint/types" "github.com/evmos/ethermint/x/evm/keeper" "github.com/evmos/ethermint/x/evm/statedb" - "github.com/evmos/ethermint/x/evm/types" evmtypes "github.com/evmos/ethermint/x/evm/types" "github.com/ethereum/go-ethereum/common" @@ -89,7 +88,7 @@ func (avd EthAccountVerificationDecorator) AnteHandle( if acct == nil { acc := avd.ak.NewAccountWithAddress(ctx, from) avd.ak.SetAccount(ctx, acc) - acct = types.NewEmptyAccount() + acct = evmtypes.NewEmptyAccount() } else if acct.IsContract() { return ctx, errorsmod.Wrapf(errortypes.ErrInvalidType, "the sender is not EOA: address %s, codeHash <%s>", fromAddr, acct.CodeHash) @@ -303,7 +302,7 @@ func (ctd CanTransferDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate BaseFee: baseFee, } - stateDB := statedb.New(ctx, ctd.evmKeeper, types.NewEmptyTxConfig(common.BytesToHash(ctx.HeaderHash().Bytes()))) + stateDB := statedb.New(ctx, ctd.evmKeeper, evmtypes.NewEmptyTxConfig(common.BytesToHash(ctx.HeaderHash().Bytes()))) evm := ctd.evmKeeper.NewEVM(ctx, coreMsg, cfg, evmtypes.NewNoOpTracer(), stateDB) // check that caller has enough balance to cover asset transfer for **topmost** call From 037a78ba46267aaf2e73ff323361e403f6d07435 Mon Sep 17 00:00:00 2001 From: drklee3 Date: Thu, 8 Feb 2024 13:55:49 -0800 Subject: [PATCH 05/10] Remove unused allow-leading-space nolintlint option removed from golangci-lint in v1.49.0 --- .golangci.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.golangci.yml b/.golangci.yml index 96e1bc311f..5765ec22e0 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -61,7 +61,6 @@ linters-settings: locale: US nolintlint: allow-unused: false - allow-leading-space: true require-explanation: false require-specific: false gofumpt: From 4410e3a5411a9cf7ef0a43abc2687ceddb285beb Mon Sep 17 00:00:00 2001 From: drklee3 Date: Thu, 8 Feb 2024 14:10:35 -0800 Subject: [PATCH 06/10] resolve lint errors --- app/upgrades.go | 2 +- rpc/websockets.go | 2 +- x/feemarket/client/cli/query.go | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/upgrades.go b/app/upgrades.go index 6b6fe2f803..deded1ad3f 100644 --- a/app/upgrades.go +++ b/app/upgrades.go @@ -23,7 +23,7 @@ import ( func (app *EthermintApp) RegisterUpgradeHandlers() { planName := "integration-test-upgrade" - app.UpgradeKeeper.SetUpgradeHandler(planName, func(ctx sdk.Context, plan upgradetypes.Plan, fromVM module.VersionMap) (module.VersionMap, error) { + app.UpgradeKeeper.SetUpgradeHandler(planName, func(ctx sdk.Context, _ upgradetypes.Plan, fromVM module.VersionMap) (module.VersionMap, error) { return app.mm.RunMigrations(ctx, app.configurator, fromVM) }) } diff --git a/rpc/websockets.go b/rpc/websockets.go index f13e2c2b77..1904855043 100644 --- a/rpc/websockets.go +++ b/rpc/websockets.go @@ -128,7 +128,7 @@ func (s *websocketsServer) Start() { func (s *websocketsServer) ServeHTTP(w http.ResponseWriter, r *http.Request) { upgrader := websocket.Upgrader{ - CheckOrigin: func(r *http.Request) bool { + CheckOrigin: func(_ *http.Request) bool { return true }, } diff --git a/x/feemarket/client/cli/query.go b/x/feemarket/client/cli/query.go index 79c281f879..78a5b1159e 100644 --- a/x/feemarket/client/cli/query.go +++ b/x/feemarket/client/cli/query.go @@ -50,7 +50,7 @@ func GetBlockGasCmd() *cobra.Command { Long: `Get the block gas used at a given block height. If the height is not provided, it will use the latest height from context`, Args: cobra.NoArgs, - RunE: func(cmd *cobra.Command, args []string) error { + RunE: func(cmd *cobra.Command, _ []string) error { clientCtx, err := client.GetClientQueryContext(cmd) if err != nil { return err @@ -108,7 +108,7 @@ func GetBaseFeeCmd() *cobra.Command { Long: `Get the base fee amount at a given block height. If the height is not provided, it will use the latest height from context.`, Args: cobra.NoArgs, - RunE: func(cmd *cobra.Command, args []string) error { + RunE: func(cmd *cobra.Command, _ []string) error { clientCtx, err := client.GetClientQueryContext(cmd) if err != nil { return err From 288e48c6e218b35ea40b9f66a1ecb8a338ee7cb7 Mon Sep 17 00:00:00 2001 From: drklee3 Date: Thu, 8 Feb 2024 14:13:46 -0800 Subject: [PATCH 07/10] ci: Run workflows on kava/release/** branches --- .github/workflows/build.yml | 3 ++- .github/workflows/labeler.yml | 6 +++--- .github/workflows/lint.yml | 5 +++-- .github/workflows/security.yml | 1 + .github/workflows/test.yml | 1 + 5 files changed, 10 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 6a1df90ae6..22c0381905 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -3,6 +3,7 @@ on: pull_request: branches: - main + - kava/release/** jobs: cleanup-runs: @@ -19,7 +20,7 @@ jobs: - uses: actions/checkout@v3 - uses: actions/setup-go@v3 with: - go-version: '1.20' + go-version: "1.20" check-latest: true - uses: technote-space/get-diff-action@v6.1.2 id: git_diff diff --git a/.github/workflows/labeler.yml b/.github/workflows/labeler.yml index a897fd5d16..4dc39dd5af 100644 --- a/.github/workflows/labeler.yml +++ b/.github/workflows/labeler.yml @@ -9,6 +9,6 @@ jobs: triage: runs-on: ubuntu-latest steps: - - uses: actions/labeler@v4 - with: - repo-token: "${{ secrets.GITHUB_TOKEN }}" + - uses: actions/labeler@v4 + with: + repo-token: "${{ secrets.GITHUB_TOKEN }}" diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 1c23449110..6a60177f4f 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -7,6 +7,7 @@ on: push: branches: - main + - kava/release/** jobs: golangci: name: Run golangci-lint @@ -16,7 +17,7 @@ jobs: # Required: setup-go, for all versions v3.0.0+ of golangci-lint - uses: actions/setup-go@v3 with: - go-version: '1.20' + go-version: "1.20" check-latest: true - uses: actions/checkout@v3 - uses: technote-space/get-diff-action@v6.1.2 @@ -25,7 +26,7 @@ jobs: **/**.go go.mod go.sum - - uses: golangci/golangci-lint-action@v3.3.1 + - uses: golangci/golangci-lint-action@v3.7.0 with: # Required: the version of golangci-lint is required and must be specified without patch version: we always use the latest patch version. version: latest diff --git a/.github/workflows/security.yml b/.github/workflows/security.yml index c0541dd72a..856520c133 100644 --- a/.github/workflows/security.yml +++ b/.github/workflows/security.yml @@ -4,6 +4,7 @@ on: push: branches: - main + - kava/release/** jobs: Gosec: diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 70099b6b8e..ffa6e9d1e5 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -5,6 +5,7 @@ on: branches: - main - release/** + - kava/release/** jobs: cleanup-runs: From 54560be48ef0e1a6aba69cc5a7df1b000b1a44d0 Mon Sep 17 00:00:00 2001 From: drklee3 Date: Fri, 9 Feb 2024 12:29:21 -0800 Subject: [PATCH 08/10] Revert "fix: Resolve importer test Statedb types" This reverts commit f18fd53909e929a63d31e98fb328b699087e0f91. --- tests/importer/importer_test.go | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/tests/importer/importer_test.go b/tests/importer/importer_test.go index 04e8918e29..a32a730206 100644 --- a/tests/importer/importer_test.go +++ b/tests/importer/importer_test.go @@ -18,8 +18,6 @@ import ( evmkeeper "github.com/evmos/ethermint/x/evm/keeper" "github.com/evmos/ethermint/x/evm/statedb" - evmtypes "github.com/evmos/ethermint/x/evm/types" - "github.com/evmos/ethermint/x/evm/vm" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/consensus/ethash" @@ -142,7 +140,7 @@ func (suite *ImporterTestSuite) TestImportBlocks() { }) ctx := suite.app.NewContext(false, tmheader) ctx = ctx.WithBlockHeight(tmheader.Height) - vmdb := statedb.New(ctx, suite.app.EvmKeeper, evmtypes.NewEmptyTxConfig(common.BytesToHash(ctx.HeaderHash().Bytes()))) + vmdb := statedb.New(ctx, suite.app.EvmKeeper, statedb.NewEmptyTxConfig(common.BytesToHash(ctx.HeaderHash().Bytes()))) if chainConfig.DAOForkSupport && chainConfig.DAOForkBlock != nil && chainConfig.DAOForkBlock.Cmp(block.Number()) == 0 { applyDAOHardFork(vmdb) @@ -228,7 +226,7 @@ func applyDAOHardFork(vmdb ethvm.StateDB) { // Ref: https://github.com/ethereum/go-ethereum/blob/52f2461774bcb8cdd310f86b4bc501df5b783852/core/state_processor.go#L88 func applyTransaction( ctx sdk.Context, config *ethparams.ChainConfig, bc ethcore.ChainContext, author *common.Address, - gp *ethcore.GasPool, evmKeeper *evmkeeper.Keeper, vmdb vm.StateDB, header *ethtypes.Header, + gp *ethcore.GasPool, evmKeeper *evmkeeper.Keeper, vmdb *statedb.StateDB, header *ethtypes.Header, tx *ethtypes.Transaction, usedGas *uint64, cfg ethvm.Config, ) (*ethtypes.Receipt, uint64, error) { msg, err := tx.AsMessage(ethtypes.MakeSigner(config, header.Number), sdk.ZeroInt().BigInt()) From d5c1221b8d0f23fd26c1a99ba6f4fd1460331831 Mon Sep 17 00:00:00 2001 From: drklee3 Date: Fri, 9 Feb 2024 12:30:34 -0800 Subject: [PATCH 09/10] Revert "Update statedb usage in app" This reverts commit 8644185d9826dafae0c41a8500e4c2ea07ab2008. --- app/ante/eth.go | 4 ++-- app/ante/eth_test.go | 8 ++++---- app/ante/interfaces.go | 2 +- app/ante/sigs_test.go | 4 ++-- app/ante/utils_test.go | 5 ++--- app/app.go | 3 +-- 6 files changed, 12 insertions(+), 14 deletions(-) diff --git a/app/ante/eth.go b/app/ante/eth.go index 669afccf3c..2402167be7 100644 --- a/app/ante/eth.go +++ b/app/ante/eth.go @@ -88,7 +88,7 @@ func (avd EthAccountVerificationDecorator) AnteHandle( if acct == nil { acc := avd.ak.NewAccountWithAddress(ctx, from) avd.ak.SetAccount(ctx, acc) - acct = evmtypes.NewEmptyAccount() + acct = statedb.NewEmptyAccount() } else if acct.IsContract() { return ctx, errorsmod.Wrapf(errortypes.ErrInvalidType, "the sender is not EOA: address %s, codeHash <%s>", fromAddr, acct.CodeHash) @@ -302,7 +302,7 @@ func (ctd CanTransferDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate BaseFee: baseFee, } - stateDB := statedb.New(ctx, ctd.evmKeeper, evmtypes.NewEmptyTxConfig(common.BytesToHash(ctx.HeaderHash().Bytes()))) + stateDB := statedb.New(ctx, ctd.evmKeeper, statedb.NewEmptyTxConfig(common.BytesToHash(ctx.HeaderHash().Bytes()))) evm := ctd.evmKeeper.NewEVM(ctx, coreMsg, cfg, evmtypes.NewNoOpTracer(), stateDB) // check that caller has enough balance to cover asset transfer for **topmost** call diff --git a/app/ante/eth_test.go b/app/ante/eth_test.go index b5dd9dd7f1..0fb9ea8b20 100644 --- a/app/ante/eth_test.go +++ b/app/ante/eth_test.go @@ -10,8 +10,8 @@ import ( "github.com/evmos/ethermint/server/config" "github.com/evmos/ethermint/tests" ethermint "github.com/evmos/ethermint/types" + "github.com/evmos/ethermint/x/evm/statedb" evmtypes "github.com/evmos/ethermint/x/evm/types" - "github.com/evmos/ethermint/x/evm/vm" ethtypes "github.com/ethereum/go-ethereum/core/types" ) @@ -26,7 +26,7 @@ func (suite AnteTestSuite) TestNewEthAccountVerificationDecorator() { tx := evmtypes.NewTxContract(suite.app.EvmKeeper.ChainID(), 1, big.NewInt(10), 1000, big.NewInt(1), nil, nil, nil, nil) tx.From = addr.Hex() - var vmdb vm.StateDB + var vmdb *statedb.StateDB testCases := []struct { name string @@ -192,7 +192,7 @@ func (suite AnteTestSuite) TestEthGasConsumeDecorator() { dynamicFeeTx.From = addr.Hex() dynamicFeeTxPriority := int64(1) - var vmdb vm.StateDB + var vmdb *statedb.StateDB testCases := []struct { name string @@ -352,7 +352,7 @@ func (suite AnteTestSuite) TestCanTransferDecorator() { err := tx.Sign(suite.ethSigner, tests.NewSigner(privKey)) suite.Require().NoError(err) - var vmdb vm.StateDB + var vmdb *statedb.StateDB testCases := []struct { name string diff --git a/app/ante/interfaces.go b/app/ante/interfaces.go index c2bb63cd62..e48e0a50a4 100644 --- a/app/ante/interfaces.go +++ b/app/ante/interfaces.go @@ -41,7 +41,7 @@ type DynamicFeeEVMKeeper interface { // EVMKeeper defines the expected keeper interface used on the Eth AnteHandler type EVMKeeper interface { - evm.StateDBKeeper + statedb.Keeper DynamicFeeEVMKeeper NewEVM(ctx sdk.Context, msg core.Message, cfg *statedb.EVMConfig, tracer vm.EVMLogger, stateDB vm.StateDB) evm.EVM diff --git a/app/ante/sigs_test.go b/app/ante/sigs_test.go index be87ab15f3..0c7b0539c8 100644 --- a/app/ante/sigs_test.go +++ b/app/ante/sigs_test.go @@ -4,7 +4,7 @@ import ( "math/big" "github.com/evmos/ethermint/tests" - "github.com/evmos/ethermint/x/evm/types" + "github.com/evmos/ethermint/x/evm/statedb" evmtypes "github.com/evmos/ethermint/x/evm/types" ) @@ -15,7 +15,7 @@ func (suite AnteTestSuite) TestSignatures() { addr, privKey := tests.NewAddrKey() to := tests.GenerateAddress() - acc := types.NewEmptyAccount() + acc := statedb.NewEmptyAccount() acc.Nonce = 1 acc.Balance = big.NewInt(10000000000) diff --git a/app/ante/utils_test.go b/app/ante/utils_test.go index e87c82e839..c92961c391 100644 --- a/app/ante/utils_test.go +++ b/app/ante/utils_test.go @@ -53,7 +53,6 @@ import ( "github.com/evmos/ethermint/tests" "github.com/evmos/ethermint/x/evm/statedb" evmtypes "github.com/evmos/ethermint/x/evm/types" - "github.com/evmos/ethermint/x/evm/vm" feemarkettypes "github.com/evmos/ethermint/x/feemarket/types" tmproto "github.com/tendermint/tendermint/proto/tendermint/types" @@ -74,8 +73,8 @@ type AnteTestSuite struct { const TestGasLimit uint64 = 100000 -func (suite *AnteTestSuite) StateDB() vm.StateDB { - return statedb.New(suite.ctx, suite.app.EvmKeeper, evmtypes.NewEmptyTxConfig(common.BytesToHash(suite.ctx.HeaderHash().Bytes()))) +func (suite *AnteTestSuite) StateDB() *statedb.StateDB { + return statedb.New(suite.ctx, suite.app.EvmKeeper, statedb.NewEmptyTxConfig(common.BytesToHash(suite.ctx.HeaderHash().Bytes()))) } func (suite *AnteTestSuite) SetupTest() { diff --git a/app/app.go b/app/app.go index 7191014db5..7b5f98d319 100644 --- a/app/app.go +++ b/app/app.go @@ -123,7 +123,6 @@ import ( ethermint "github.com/evmos/ethermint/types" "github.com/evmos/ethermint/x/evm" evmkeeper "github.com/evmos/ethermint/x/evm/keeper" - "github.com/evmos/ethermint/x/evm/statedb" evmtypes "github.com/evmos/ethermint/x/evm/types" legacyevmtypes "github.com/evmos/ethermint/x/evm/types/legacy" "github.com/evmos/ethermint/x/evm/vm/geth" @@ -423,7 +422,7 @@ func NewEthermintApp( appCodec, keys[evmtypes.StoreKey], tkeys[evmtypes.TransientKey], authtypes.NewModuleAddress(govtypes.ModuleName), app.AccountKeeper, app.BankKeeper, app.StakingKeeper, app.FeeMarketKeeper, - nil, geth.NewEVM, statedb.New, tracer, evmSs, + nil, geth.NewEVM, tracer, evmSs, ) // Create IBC Keeper From a54e471614a0cfc11646c684932a6a4390e07f3d Mon Sep 17 00:00:00 2001 From: drklee3 Date: Fri, 9 Feb 2024 12:30:44 -0800 Subject: [PATCH 10/10] Revert "refactor(evm): Move StateDB types, use StateDB interface in keeper" This reverts commit 1ddf4355517add1d90a8ac7459e647ee1df4efaa. --- x/evm/genesis_test.go | 4 +- x/evm/handler_test.go | 5 +-- x/evm/keeper/config.go | 4 +- x/evm/keeper/grpc_query.go | 10 ++--- x/evm/keeper/grpc_query_test.go | 2 +- x/evm/keeper/hooks_test.go | 2 +- x/evm/keeper/keeper.go | 39 ++++++++--------- x/evm/keeper/keeper_test.go | 11 ++--- x/evm/keeper/msg_server_test.go | 4 +- x/evm/keeper/params_test.go | 4 -- x/evm/keeper/state_transition.go | 6 +-- x/evm/keeper/state_transition_test.go | 5 +-- x/evm/keeper/statedb.go | 8 ++-- x/evm/keeper/statedb_test.go | 20 ++++----- x/evm/migrations/v3/store_test.go | 2 - x/evm/statedb/config.go | 29 +++++++++++++ x/evm/statedb/interfaces.go | 18 ++++++++ x/evm/statedb/mock_test.go | 14 +++--- x/evm/statedb/state_object.go | 26 ++++++++++-- x/evm/statedb/statedb.go | 12 +++--- x/evm/statedb/statedb_test.go | 44 +++++++++---------- x/evm/types/statedb.go | 61 --------------------------- x/evm/vm/interface.go | 44 ------------------- 23 files changed, 156 insertions(+), 218 deletions(-) delete mode 100644 x/evm/types/statedb.go diff --git a/x/evm/genesis_test.go b/x/evm/genesis_test.go index 72262472e9..e060c5d965 100644 --- a/x/evm/genesis_test.go +++ b/x/evm/genesis_test.go @@ -9,8 +9,8 @@ import ( "github.com/evmos/ethermint/crypto/ethsecp256k1" etherminttypes "github.com/evmos/ethermint/types" "github.com/evmos/ethermint/x/evm" + "github.com/evmos/ethermint/x/evm/statedb" "github.com/evmos/ethermint/x/evm/types" - "github.com/evmos/ethermint/x/evm/vm" ) func (suite *EvmTestSuite) TestInitGenesis() { @@ -19,7 +19,7 @@ func (suite *EvmTestSuite) TestInitGenesis() { address := common.HexToAddress(privkey.PubKey().Address().String()) - var vmdb vm.StateDB + var vmdb *statedb.StateDB testCases := []struct { name string diff --git a/x/evm/handler_test.go b/x/evm/handler_test.go index 68b2b74a1b..a554c6ee6a 100644 --- a/x/evm/handler_test.go +++ b/x/evm/handler_test.go @@ -7,7 +7,6 @@ import ( "time" "github.com/evmos/ethermint/x/evm/keeper" - "github.com/evmos/ethermint/x/evm/vm" sdkmath "cosmossdk.io/math" "github.com/gogo/protobuf/proto" @@ -182,8 +181,8 @@ func (suite *EvmTestSuite) SignTx(tx *types.MsgEthereumTx) { suite.Require().NoError(err) } -func (suite *EvmTestSuite) StateDB() vm.StateDB { - return statedb.New(suite.ctx, suite.app.EvmKeeper, types.NewEmptyTxConfig(common.BytesToHash(suite.ctx.HeaderHash().Bytes()))) +func (suite *EvmTestSuite) StateDB() *statedb.StateDB { + return statedb.New(suite.ctx, suite.app.EvmKeeper, statedb.NewEmptyTxConfig(common.BytesToHash(suite.ctx.HeaderHash().Bytes()))) } func TestEvmTestSuite(t *testing.T) { diff --git a/x/evm/keeper/config.go b/x/evm/keeper/config.go index 1d76fd0d06..3debb895de 100644 --- a/x/evm/keeper/config.go +++ b/x/evm/keeper/config.go @@ -48,8 +48,8 @@ func (k *Keeper) EVMConfig(ctx sdk.Context, proposerAddress sdk.ConsAddress, cha } // TxConfig loads `TxConfig` from current transient storage -func (k *Keeper) TxConfig(ctx sdk.Context, txHash common.Hash) types.TxConfig { - return types.NewTxConfig( +func (k *Keeper) TxConfig(ctx sdk.Context, txHash common.Hash) statedb.TxConfig { + return statedb.NewTxConfig( common.BytesToHash(ctx.HeaderHash()), // BlockHash txHash, // TxHash uint(k.GetTxIndexTransient(ctx)), // TxIndex diff --git a/x/evm/keeper/grpc_query.go b/x/evm/keeper/grpc_query.go index f9d5b5e56f..5e09153b59 100644 --- a/x/evm/keeper/grpc_query.go +++ b/x/evm/keeper/grpc_query.go @@ -255,7 +255,7 @@ func (k Keeper) EthCall(c context.Context, req *types.EthCallRequest) (*types.Ms return nil, status.Error(codes.InvalidArgument, err.Error()) } - txConfig := types.NewEmptyTxConfig(common.BytesToHash(ctx.HeaderHash())) + txConfig := statedb.NewEmptyTxConfig(common.BytesToHash(ctx.HeaderHash())) // pass false to not commit StateDB res, err := k.ApplyMessageWithConfig(ctx, msg, nil, false, cfg, txConfig) @@ -324,7 +324,7 @@ func (k Keeper) EstimateGas(c context.Context, req *types.EthCallRequest) (*type nonce := k.GetNonce(ctx, args.GetFrom()) args.Nonce = (*hexutil.Uint64)(&nonce) - txConfig := types.NewEmptyTxConfig(common.BytesToHash(ctx.HeaderHash().Bytes())) + txConfig := statedb.NewEmptyTxConfig(common.BytesToHash(ctx.HeaderHash().Bytes())) // convert the tx args to an ethereum message msg, err := args.ToMessage(req.GasCap, cfg.BaseFee) @@ -423,7 +423,7 @@ func (k Keeper) TraceTx(c context.Context, req *types.QueryTraceTxRequest) (*typ } signer := ethtypes.MakeSigner(cfg.ChainConfig, big.NewInt(ctx.BlockHeight())) - txConfig := types.NewEmptyTxConfig(common.BytesToHash(ctx.HeaderHash().Bytes())) + txConfig := statedb.NewEmptyTxConfig(common.BytesToHash(ctx.HeaderHash().Bytes())) for i, tx := range req.Predecessors { ethTx := tx.AsTransaction() msg, err := ethTx.AsMessage(signer, cfg.BaseFee) @@ -503,7 +503,7 @@ func (k Keeper) TraceBlock(c context.Context, req *types.QueryTraceBlockRequest) txsLength := len(req.Txs) results := make([]*types.TxTraceResult, 0, txsLength) - txConfig := types.NewEmptyTxConfig(common.BytesToHash(ctx.HeaderHash().Bytes())) + txConfig := statedb.NewEmptyTxConfig(common.BytesToHash(ctx.HeaderHash().Bytes())) for i, tx := range req.Txs { result := types.TxTraceResult{} ethTx := tx.AsTransaction() @@ -533,7 +533,7 @@ func (k Keeper) TraceBlock(c context.Context, req *types.QueryTraceBlockRequest) func (k *Keeper) traceTx( ctx sdk.Context, cfg *statedb.EVMConfig, - txConfig types.TxConfig, + txConfig statedb.TxConfig, signer ethtypes.Signer, tx *ethtypes.Transaction, traceConfig *types.TraceConfig, diff --git a/x/evm/keeper/grpc_query_test.go b/x/evm/keeper/grpc_query_test.go index 50849abf49..4149aa47f3 100644 --- a/x/evm/keeper/grpc_query_test.go +++ b/x/evm/keeper/grpc_query_test.go @@ -392,7 +392,7 @@ func (suite *KeeperTestSuite) TestQueryTxLogs() { suite.Run(fmt.Sprintf("Case %s", tc.msg), func() { suite.SetupTest() // reset - vmdb := statedb.New(suite.ctx, suite.app.EvmKeeper, types.NewTxConfig(common.BytesToHash(suite.ctx.HeaderHash().Bytes()), txHash, txIndex, logIndex)) + vmdb := statedb.New(suite.ctx, suite.app.EvmKeeper, statedb.NewTxConfig(common.BytesToHash(suite.ctx.HeaderHash().Bytes()), txHash, txIndex, logIndex)) tc.malleate(vmdb) suite.Require().NoError(vmdb.Commit()) diff --git a/x/evm/keeper/hooks_test.go b/x/evm/keeper/hooks_test.go index 27f6dc58a0..b635cf4cd4 100644 --- a/x/evm/keeper/hooks_test.go +++ b/x/evm/keeper/hooks_test.go @@ -66,7 +66,7 @@ func (suite *KeeperTestSuite) TestEvmHooks() { k := suite.app.EvmKeeper ctx := suite.ctx txHash := common.BigToHash(big.NewInt(1)) - vmdb := statedb.New(ctx, k, types.NewTxConfig( + vmdb := statedb.New(ctx, k, statedb.NewTxConfig( common.BytesToHash(ctx.HeaderHash().Bytes()), txHash, 0, diff --git a/x/evm/keeper/keeper.go b/x/evm/keeper/keeper.go index 45e804dbfe..9c47491d8d 100644 --- a/x/evm/keeper/keeper.go +++ b/x/evm/keeper/keeper.go @@ -32,6 +32,7 @@ import ( "github.com/tendermint/tendermint/libs/log" ethermint "github.com/evmos/ethermint/types" + "github.com/evmos/ethermint/x/evm/statedb" "github.com/evmos/ethermint/x/evm/types" legacytypes "github.com/evmos/ethermint/x/evm/types/legacy" evm "github.com/evmos/ethermint/x/evm/vm" @@ -76,10 +77,6 @@ type Keeper struct { // evm constructor function evmConstructor evm.Constructor - - // stateDB constructor function - stateDBConstructor evm.StateDBConstructor - // Legacy subspace ss paramstypes.Subspace } @@ -95,7 +92,6 @@ func NewKeeper( fmk types.FeeMarketKeeper, customPrecompiles evm.PrecompiledContracts, evmConstructor evm.Constructor, - stateDBConstructor evm.StateDBConstructor, tracer string, ss paramstypes.Subspace, ) *Keeper { @@ -115,19 +111,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, - stateDBConstructor: stateDBConstructor, - tracer: tracer, - ss: ss, + cdc: cdc, + authority: authority, + accountKeeper: ak, + bankKeeper: bankKeeper, + stakingKeeper: sk, + feeMarketKeeper: fmk, + storeKey: storeKey, + transientKey: transientKey, + customPrecompiles: customPrecompiles, + evmConstructor: evmConstructor, + tracer: tracer, + ss: ss, } } @@ -284,7 +279,7 @@ func (k Keeper) Tracer(ctx sdk.Context, msg core.Message, ethCfg *params.ChainCo // GetAccountWithoutBalance load nonce and codehash without balance, // more efficient in cases where balance is not needed. -func (k *Keeper) GetAccountWithoutBalance(ctx sdk.Context, addr common.Address) *types.StateDBAccount { +func (k *Keeper) GetAccountWithoutBalance(ctx sdk.Context, addr common.Address) *statedb.Account { cosmosAddr := sdk.AccAddress(addr.Bytes()) acct := k.accountKeeper.GetAccount(ctx, cosmosAddr) if acct == nil { @@ -297,21 +292,21 @@ func (k *Keeper) GetAccountWithoutBalance(ctx sdk.Context, addr common.Address) codeHash = ethAcct.GetCodeHash().Bytes() } - return &types.StateDBAccount{ + return &statedb.Account{ Nonce: acct.GetSequence(), CodeHash: codeHash, } } // GetAccountOrEmpty returns empty account if not exist, returns error if it's not `EthAccount` -func (k *Keeper) GetAccountOrEmpty(ctx sdk.Context, addr common.Address) types.StateDBAccount { +func (k *Keeper) GetAccountOrEmpty(ctx sdk.Context, addr common.Address) statedb.Account { acct := k.GetAccount(ctx, addr) if acct != nil { return *acct } // empty account - return types.StateDBAccount{ + return statedb.Account{ Balance: new(big.Int), CodeHash: types.EmptyCodeHash, } diff --git a/x/evm/keeper/keeper_test.go b/x/evm/keeper/keeper_test.go index 826a8f53cc..1b89527735 100644 --- a/x/evm/keeper/keeper_test.go +++ b/x/evm/keeper/keeper_test.go @@ -37,7 +37,6 @@ import ( "github.com/evmos/ethermint/x/evm/statedb" "github.com/evmos/ethermint/x/evm/types" evmtypes "github.com/evmos/ethermint/x/evm/types" - "github.com/evmos/ethermint/x/evm/vm" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" @@ -253,12 +252,8 @@ func (suite *KeeperTestSuite) Commit() { suite.queryClient = types.NewQueryClient(queryHelper) } -func (suite *KeeperTestSuite) StateDB() vm.StateDB { - return statedb.New( - suite.ctx, - suite.app.EvmKeeper, - types.NewEmptyTxConfig(common.BytesToHash(suite.ctx.HeaderHash().Bytes())), - ) +func (suite *KeeperTestSuite) StateDB() *statedb.StateDB { + return statedb.New(suite.ctx, suite.app.EvmKeeper, statedb.NewEmptyTxConfig(common.BytesToHash(suite.ctx.HeaderHash().Bytes()))) } // DeployTestContract deploy a test erc20 contract and returns the contract address @@ -503,7 +498,7 @@ func (suite *KeeperTestSuite) TestGetAccountStorage() { } func (suite *KeeperTestSuite) TestGetAccountOrEmpty() { - empty := types.StateDBAccount{ + empty := statedb.Account{ Balance: new(big.Int), CodeHash: types.EmptyCodeHash, } diff --git a/x/evm/keeper/msg_server_test.go b/x/evm/keeper/msg_server_test.go index 39e4ae5383..4a8c86cefa 100644 --- a/x/evm/keeper/msg_server_test.go +++ b/x/evm/keeper/msg_server_test.go @@ -8,8 +8,8 @@ import ( ethtypes "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/params" + "github.com/evmos/ethermint/x/evm/statedb" "github.com/evmos/ethermint/x/evm/types" - "github.com/evmos/ethermint/x/evm/vm" ) func (suite *KeeperTestSuite) TestEthereumTx() { @@ -17,7 +17,7 @@ func (suite *KeeperTestSuite) TestEthereumTx() { err error msg *types.MsgEthereumTx signer ethtypes.Signer - vmdb vm.StateDB + vmdb *statedb.StateDB chainCfg *params.ChainConfig expectedGasUsed uint64 ) diff --git a/x/evm/keeper/params_test.go b/x/evm/keeper/params_test.go index 56b7e7b9b0..af64009aab 100644 --- a/x/evm/keeper/params_test.go +++ b/x/evm/keeper/params_test.go @@ -11,7 +11,6 @@ import ( "github.com/evmos/ethermint/app" "github.com/evmos/ethermint/encoding" "github.com/evmos/ethermint/x/evm/keeper" - "github.com/evmos/ethermint/x/evm/statedb" "github.com/evmos/ethermint/x/evm/types" legacytypes "github.com/evmos/ethermint/x/evm/types/legacy" legacytestutil "github.com/evmos/ethermint/x/evm/types/legacy/testutil" @@ -153,7 +152,6 @@ func (suite *KeeperTestSuite) TestLegacyParamsKeyTableRegistration() { ak, nil, nil, nil, nil, // OK to pass nil in for these since we only instantiate and use params geth.NewEVM, - statedb.New, "", unregisteredSubspace, ) @@ -211,7 +209,6 @@ func (suite *KeeperTestSuite) TestRenamedFieldReturnsProperValueForLegacyParams( ak, nil, nil, nil, nil, geth.NewEVM, - statedb.New, "", subspace, ) @@ -244,7 +241,6 @@ func (suite *KeeperTestSuite) TestNilLegacyParamsDoNotPanic() { ak, nil, nil, nil, nil, // OK to pass nil in for these since we only instantiate and use params geth.NewEVM, - statedb.New, "", subspace, ) diff --git a/x/evm/keeper/state_transition.go b/x/evm/keeper/state_transition.go index ef02cdc3c3..ad90dba5fd 100644 --- a/x/evm/keeper/state_transition.go +++ b/x/evm/keeper/state_transition.go @@ -268,7 +268,7 @@ func (k *Keeper) ApplyMessage(ctx sdk.Context, msg core.Message, tracer vm.EVMLo return nil, errorsmod.Wrap(err, "failed to load evm config") } - txConfig := types.NewEmptyTxConfig(common.BytesToHash(ctx.HeaderHash())) + txConfig := statedb.NewEmptyTxConfig(common.BytesToHash(ctx.HeaderHash())) return k.ApplyMessageWithConfig(ctx, msg, tracer, commit, cfg, txConfig) } @@ -315,7 +315,7 @@ func (k *Keeper) ApplyMessageWithConfig(ctx sdk.Context, tracer vm.EVMLogger, commit bool, cfg *statedb.EVMConfig, - txConfig types.TxConfig, + txConfig statedb.TxConfig, ) (*types.MsgEthereumTxResponse, error) { var ( ret []byte // return bytes from evm execution @@ -329,7 +329,7 @@ func (k *Keeper) ApplyMessageWithConfig(ctx sdk.Context, return nil, errorsmod.Wrap(types.ErrCallDisabled, "failed to call contract") } - stateDB := k.stateDBConstructor(ctx, k, txConfig) + stateDB := statedb.New(ctx, k, txConfig) evm := k.NewEVM(ctx, msg, cfg, tracer, stateDB) leftoverGas := msg.Gas() diff --git a/x/evm/keeper/state_transition_test.go b/x/evm/keeper/state_transition_test.go index f1fba5f00c..b74f681d6b 100644 --- a/x/evm/keeper/state_transition_test.go +++ b/x/evm/keeper/state_transition_test.go @@ -11,7 +11,6 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core" ethtypes "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/params" "github.com/evmos/ethermint/tests" "github.com/evmos/ethermint/x/evm/keeper" @@ -575,8 +574,8 @@ func (suite *KeeperTestSuite) TestApplyMessageWithConfig() { config *statedb.EVMConfig keeperParams types.Params signer ethtypes.Signer - vmdb vm.StateDB - txConfig types.TxConfig + vmdb *statedb.StateDB + txConfig statedb.TxConfig chainCfg *params.ChainConfig ) diff --git a/x/evm/keeper/statedb.go b/x/evm/keeper/statedb.go index 7644798354..c2cd893c5e 100644 --- a/x/evm/keeper/statedb.go +++ b/x/evm/keeper/statedb.go @@ -27,18 +27,18 @@ import ( authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" "github.com/ethereum/go-ethereum/common" ethermint "github.com/evmos/ethermint/types" + "github.com/evmos/ethermint/x/evm/statedb" "github.com/evmos/ethermint/x/evm/types" - "github.com/evmos/ethermint/x/evm/vm" ) -var _ vm.StateDBKeeper = &Keeper{} +var _ statedb.Keeper = &Keeper{} // ---------------------------------------------------------------------------- // StateDB Keeper implementation // ---------------------------------------------------------------------------- // GetAccount returns nil if account is not exist, returns error if it's not `EthAccountI` -func (k *Keeper) GetAccount(ctx sdk.Context, addr common.Address) *types.StateDBAccount { +func (k *Keeper) GetAccount(ctx sdk.Context, addr common.Address) *statedb.Account { acct := k.GetAccountWithoutBalance(ctx, addr) if acct == nil { return nil @@ -119,7 +119,7 @@ func (k *Keeper) SetBalance(ctx sdk.Context, addr common.Address, amount *big.In } // SetAccount updates nonce/balance/codeHash together. -func (k *Keeper) SetAccount(ctx sdk.Context, addr common.Address, account types.StateDBAccount) error { +func (k *Keeper) SetAccount(ctx sdk.Context, addr common.Address, account statedb.Account) error { // update account cosmosAddr := sdk.AccAddress(addr.Bytes()) acct := k.accountKeeper.GetAccount(ctx, cosmosAddr) diff --git a/x/evm/keeper/statedb_test.go b/x/evm/keeper/statedb_test.go index af60a73d9c..fecb8392f5 100644 --- a/x/evm/keeper/statedb_test.go +++ b/x/evm/keeper/statedb_test.go @@ -233,55 +233,55 @@ func (suite *KeeperTestSuite) TestSetAccount() { testCases := []struct { name string address common.Address - account types.StateDBAccount + account statedb.Account expectedErr error }{ { "new account, non-contract account", tests.GenerateAddress(), - types.StateDBAccount{10, big.NewInt(100), types.EmptyCodeHash}, + statedb.Account{10, big.NewInt(100), types.EmptyCodeHash}, nil, }, { "new account, contract account", tests.GenerateAddress(), - types.StateDBAccount{10, big.NewInt(100), crypto.Keccak256Hash([]byte("some code hash")).Bytes()}, + statedb.Account{10, big.NewInt(100), crypto.Keccak256Hash([]byte("some code hash")).Bytes()}, nil, }, { "existing eth account, non-contract account", ethAddr, - types.StateDBAccount{10, big.NewInt(1), types.EmptyCodeHash}, + statedb.Account{10, big.NewInt(1), types.EmptyCodeHash}, nil, }, { "existing eth account, contract account", ethAddr, - types.StateDBAccount{10, big.NewInt(0), crypto.Keccak256Hash([]byte("some code hash")).Bytes()}, + statedb.Account{10, big.NewInt(0), crypto.Keccak256Hash([]byte("some code hash")).Bytes()}, nil, }, { "existing base account, non-contract account", baseAddr, - types.StateDBAccount{10, big.NewInt(10), types.EmptyCodeHash}, + statedb.Account{10, big.NewInt(10), types.EmptyCodeHash}, nil, }, { "existing base account, contract account", baseAddr, - types.StateDBAccount{10, big.NewInt(99), crypto.Keccak256Hash([]byte("some code hash")).Bytes()}, + statedb.Account{10, big.NewInt(99), crypto.Keccak256Hash([]byte("some code hash")).Bytes()}, nil, }, { "existing vesting account, non-contract account", vestingAddr, - types.StateDBAccount{10, big.NewInt(1000), types.EmptyCodeHash}, + statedb.Account{10, big.NewInt(1000), types.EmptyCodeHash}, nil, }, { "existing vesting account, contract account", vestingAddr, - types.StateDBAccount{10, big.NewInt(1001), crypto.Keccak256Hash([]byte("some code hash")).Bytes()}, + statedb.Account{10, big.NewInt(1001), crypto.Keccak256Hash([]byte("some code hash")).Bytes()}, types.ErrInvalidAccount, }, } @@ -791,7 +791,7 @@ func (suite *KeeperTestSuite) TestAddLog() { for _, tc := range testCases { suite.Run(tc.name, func() { suite.SetupTest() - vmdb := statedb.New(suite.ctx, suite.app.EvmKeeper, types.NewTxConfig( + vmdb := statedb.New(suite.ctx, suite.app.EvmKeeper, statedb.NewTxConfig( common.BytesToHash(suite.ctx.HeaderHash().Bytes()), tc.hash, 0, 0, diff --git a/x/evm/migrations/v3/store_test.go b/x/evm/migrations/v3/store_test.go index 12ff79409a..a01916a6f7 100644 --- a/x/evm/migrations/v3/store_test.go +++ b/x/evm/migrations/v3/store_test.go @@ -4,7 +4,6 @@ import ( "testing" "github.com/evmos/ethermint/x/evm/keeper" - "github.com/evmos/ethermint/x/evm/statedb" "github.com/evmos/ethermint/x/evm/types" "github.com/evmos/ethermint/x/evm/vm/geth" "github.com/stretchr/testify/require" @@ -152,7 +151,6 @@ func TestKeyTableCompatiabilityWithKeeper(t *testing.T) { ak, nil, nil, nil, nil, geth.NewEVM, - statedb.New, "", subspace, ) diff --git a/x/evm/statedb/config.go b/x/evm/statedb/config.go index 445ae0d47c..d9baa5387f 100644 --- a/x/evm/statedb/config.go +++ b/x/evm/statedb/config.go @@ -23,6 +23,35 @@ import ( "github.com/evmos/ethermint/x/evm/types" ) +// TxConfig encapulates the readonly information of current tx for `StateDB`. +type TxConfig struct { + BlockHash common.Hash // hash of current block + TxHash common.Hash // hash of current tx + TxIndex uint // the index of current transaction + LogIndex uint // the index of next log within current block +} + +// NewTxConfig returns a TxConfig +func NewTxConfig(bhash, thash common.Hash, txIndex, logIndex uint) TxConfig { + return TxConfig{ + BlockHash: bhash, + TxHash: thash, + TxIndex: txIndex, + LogIndex: logIndex, + } +} + +// NewEmptyTxConfig construct an empty TxConfig, +// used in context where there's no transaction, e.g. `eth_call`/`eth_estimateGas`. +func NewEmptyTxConfig(bhash common.Hash) TxConfig { + return TxConfig{ + BlockHash: bhash, + TxHash: common.Hash{}, + TxIndex: 0, + LogIndex: 0, + } +} + // EVMConfig encapsulates common parameters needed to create an EVM to execute a message // It's mainly to reduce the number of method parameters type EVMConfig struct { diff --git a/x/evm/statedb/interfaces.go b/x/evm/statedb/interfaces.go index eb8494d719..e4e83e09c3 100644 --- a/x/evm/statedb/interfaces.go +++ b/x/evm/statedb/interfaces.go @@ -16,6 +16,8 @@ package statedb import ( + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/vm" ) @@ -28,3 +30,19 @@ type ExtStateDB interface { vm.StateDB AppendJournalEntry(JournalEntry) } + +// Keeper provide underlying storage of StateDB +type Keeper interface { + // Read methods + GetAccount(ctx sdk.Context, addr common.Address) *Account + GetState(ctx sdk.Context, addr common.Address, key common.Hash) common.Hash + GetCode(ctx sdk.Context, codeHash common.Hash) []byte + // the callback returns false to break early + ForEachStorage(ctx sdk.Context, addr common.Address, cb func(key, value common.Hash) bool) + + // Write methods, only called by `StateDB.Commit()` + SetAccount(ctx sdk.Context, addr common.Address, account Account) error + SetState(ctx sdk.Context, addr common.Address, key common.Hash, value []byte) + SetCode(ctx sdk.Context, codeHash []byte, code []byte) + DeleteAccount(ctx sdk.Context, addr common.Address) error +} diff --git a/x/evm/statedb/mock_test.go b/x/evm/statedb/mock_test.go index 88c270ed5e..544cbfa1b4 100644 --- a/x/evm/statedb/mock_test.go +++ b/x/evm/statedb/mock_test.go @@ -9,18 +9,16 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" "github.com/evmos/ethermint/x/evm/statedb" - "github.com/evmos/ethermint/x/evm/types" - "github.com/evmos/ethermint/x/evm/vm" ) var ( - _ vm.StateDBKeeper = &MockKeeper{} - errAddress common.Address = common.BigToAddress(big.NewInt(100)) - emptyCodeHash = crypto.Keccak256(nil) + _ statedb.Keeper = &MockKeeper{} + errAddress common.Address = common.BigToAddress(big.NewInt(100)) + emptyCodeHash = crypto.Keccak256(nil) ) type MockAcount struct { - account types.StateDBAccount + account statedb.Account states statedb.Storage } @@ -36,7 +34,7 @@ func NewMockKeeper() *MockKeeper { } } -func (k MockKeeper) GetAccount(ctx sdk.Context, addr common.Address) *types.StateDBAccount { +func (k MockKeeper) GetAccount(ctx sdk.Context, addr common.Address) *statedb.Account { acct, ok := k.accounts[addr] if !ok { return nil @@ -62,7 +60,7 @@ func (k MockKeeper) ForEachStorage(ctx sdk.Context, addr common.Address, cb func } } -func (k MockKeeper) SetAccount(ctx sdk.Context, addr common.Address, account types.StateDBAccount) error { +func (k MockKeeper) SetAccount(ctx sdk.Context, addr common.Address, account statedb.Account) error { if addr == errAddress { return errors.New("mock db error") } diff --git a/x/evm/statedb/state_object.go b/x/evm/statedb/state_object.go index 485e836191..dd344dfadb 100644 --- a/x/evm/statedb/state_object.go +++ b/x/evm/statedb/state_object.go @@ -22,11 +22,31 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" - "github.com/evmos/ethermint/x/evm/types" ) var emptyCodeHash = crypto.Keccak256(nil) +// Account is the Ethereum consensus representation of accounts. +// These objects are stored in the storage of auth module. +type Account struct { + Nonce uint64 + Balance *big.Int + CodeHash []byte +} + +// NewEmptyAccount returns an empty account. +func NewEmptyAccount() *Account { + return &Account{ + Balance: new(big.Int), + CodeHash: emptyCodeHash, + } +} + +// IsContract returns if the account contains contract code. +func (acct Account) IsContract() bool { + return !bytes.Equal(acct.CodeHash, emptyCodeHash) +} + // Storage represents in-memory cache/buffer of contract storage. type Storage map[common.Hash]common.Hash @@ -48,7 +68,7 @@ func (s Storage) SortedKeys() []common.Hash { type stateObject struct { db *StateDB - account types.StateDBAccount + account Account code []byte // state storage @@ -63,7 +83,7 @@ type stateObject struct { } // newObject creates a state object. -func newObject(db *StateDB, address common.Address, account types.StateDBAccount) *stateObject { +func newObject(db *StateDB, address common.Address, account Account) *stateObject { if account.Balance == nil { account.Balance = new(big.Int) } diff --git a/x/evm/statedb/statedb.go b/x/evm/statedb/statedb.go index 5a254efc18..941cb0c21b 100644 --- a/x/evm/statedb/statedb.go +++ b/x/evm/statedb/statedb.go @@ -26,8 +26,6 @@ import ( ethtypes "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" - "github.com/evmos/ethermint/x/evm/types" - evm "github.com/evmos/ethermint/x/evm/vm" ) // revision is the identifier of a version of state. @@ -46,7 +44,7 @@ var _ vm.StateDB = &StateDB{} // * Contracts // * Accounts type StateDB struct { - keeper evm.StateDBKeeper + keeper Keeper ctx sdk.Context // Journal of state modifications. This is the backbone of @@ -57,7 +55,7 @@ type StateDB struct { stateObjects map[common.Address]*stateObject - txConfig types.TxConfig + txConfig TxConfig // The refund counter, also used by state transitioning. refund uint64 @@ -70,7 +68,7 @@ type StateDB struct { } // New creates a new state from a given trie. -func New(ctx sdk.Context, keeper evm.StateDBKeeper, txConfig types.TxConfig) evm.StateDB { +func New(ctx sdk.Context, keeper Keeper, txConfig TxConfig) *StateDB { return &StateDB{ keeper: keeper, ctx: ctx, @@ -83,7 +81,7 @@ func New(ctx sdk.Context, keeper evm.StateDBKeeper, txConfig types.TxConfig) evm } // Keeper returns the underlying `Keeper` -func (s *StateDB) Keeper() evm.StateDBKeeper { +func (s *StateDB) Keeper() Keeper { return s.keeper } @@ -248,7 +246,7 @@ func (s *StateDB) getOrNewStateObject(addr common.Address) *stateObject { func (s *StateDB) createObject(addr common.Address) (newobj, prev *stateObject) { prev = s.getStateObject(addr) - newobj = newObject(s, addr, types.StateDBAccount{}) + newobj = newObject(s, addr, Account{}) if prev == nil { s.journal.append(createObjectChange{account: &addr}) } else { diff --git a/x/evm/statedb/statedb_test.go b/x/evm/statedb/statedb_test.go index cac980e92e..3a491aa8cc 100644 --- a/x/evm/statedb/statedb_test.go +++ b/x/evm/statedb/statedb_test.go @@ -10,17 +10,15 @@ import ( "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" "github.com/evmos/ethermint/x/evm/statedb" - "github.com/evmos/ethermint/x/evm/types" - evm "github.com/evmos/ethermint/x/evm/vm" "github.com/stretchr/testify/suite" ) var ( - address common.Address = common.BigToAddress(big.NewInt(101)) - address2 common.Address = common.BigToAddress(big.NewInt(102)) - address3 common.Address = common.BigToAddress(big.NewInt(103)) - blockHash common.Hash = common.BigToHash(big.NewInt(9999)) - emptyTxConfig types.TxConfig = types.NewEmptyTxConfig(blockHash) + address common.Address = common.BigToAddress(big.NewInt(101)) + address2 common.Address = common.BigToAddress(big.NewInt(102)) + address3 common.Address = common.BigToAddress(big.NewInt(103)) + blockHash common.Hash = common.BigToHash(big.NewInt(9999)) + emptyTxConfig statedb.TxConfig = statedb.NewEmptyTxConfig(blockHash) ) type StateDBTestSuite struct { @@ -34,9 +32,9 @@ func (suite *StateDBTestSuite) TestAccount() { value2 := common.BigToHash(big.NewInt(4)) testCases := []struct { name string - malleate func(evm.StateDB) + malleate func(*statedb.StateDB) }{ - {"non-exist account", func(db evm.StateDB) { + {"non-exist account", func(db *statedb.StateDB) { suite.Require().Equal(false, db.Exist(address)) suite.Require().Equal(true, db.Empty(address)) suite.Require().Equal(big.NewInt(0), db.GetBalance(address)) @@ -44,13 +42,13 @@ func (suite *StateDBTestSuite) TestAccount() { suite.Require().Equal(common.Hash{}, db.GetCodeHash(address)) suite.Require().Equal(uint64(0), db.GetNonce(address)) }}, - {"empty account", func(db evm.StateDB) { + {"empty account", func(db *statedb.StateDB) { db.CreateAccount(address) suite.Require().NoError(db.Commit()) keeper := db.Keeper().(*MockKeeper) acct := keeper.accounts[address] - suite.Require().Equal(types.NewEmptyAccount(), &acct.account) + suite.Require().Equal(statedb.NewEmptyAccount(), &acct.account) suite.Require().Empty(acct.states) suite.Require().False(acct.account.IsContract()) @@ -62,7 +60,7 @@ func (suite *StateDBTestSuite) TestAccount() { suite.Require().Equal(common.BytesToHash(emptyCodeHash), db.GetCodeHash(address)) suite.Require().Equal(uint64(0), db.GetNonce(address)) }}, - {"suicide", func(db evm.StateDB) { + {"suicide", func(db *statedb.StateDB) { // non-exist account. suite.Require().False(db.Suicide(address)) suite.Require().False(db.HasSuicided(address)) @@ -152,22 +150,22 @@ func (suite *StateDBTestSuite) TestBalance() { // NOTE: no need to test overflow/underflow, that is guaranteed by evm implementation. testCases := []struct { name string - malleate func(evm.StateDB) + malleate func(*statedb.StateDB) expBalance *big.Int }{ - {"add balance", func(db evm.StateDB) { + {"add balance", func(db *statedb.StateDB) { db.AddBalance(address, big.NewInt(10)) }, big.NewInt(10)}, - {"sub balance", func(db evm.StateDB) { + {"sub balance", func(db *statedb.StateDB) { db.AddBalance(address, big.NewInt(10)) // get dirty balance suite.Require().Equal(big.NewInt(10), db.GetBalance(address)) db.SubBalance(address, big.NewInt(2)) }, big.NewInt(8)}, - {"add zero balance", func(db evm.StateDB) { + {"add zero balance", func(db *statedb.StateDB) { db.AddBalance(address, big.NewInt(0)) }, big.NewInt(0)}, - {"sub zero balance", func(db evm.StateDB) { + {"sub zero balance", func(db *statedb.StateDB) { db.SubBalance(address, big.NewInt(0)) }, big.NewInt(0)}, } @@ -192,19 +190,19 @@ func (suite *StateDBTestSuite) TestState() { value1 := common.BigToHash(big.NewInt(1)) testCases := []struct { name string - malleate func(evm.StateDB) + malleate func(*statedb.StateDB) expStates statedb.Storage }{ - {"empty state", func(db evm.StateDB) { + {"empty state", func(db *statedb.StateDB) { }, nil}, - {"set empty value", func(db evm.StateDB) { + {"set empty value", func(db *statedb.StateDB) { db.SetState(address, key1, common.Hash{}) }, statedb.Storage{}}, - {"noop state change", func(db evm.StateDB) { + {"noop state change", func(db *statedb.StateDB) { db.SetState(address, key1, value1) db.SetState(address, key1, common.Hash{}) }, statedb.Storage{}}, - {"set state", func(db evm.StateDB) { + {"set state", func(db *statedb.StateDB) { // check empty initial state suite.Require().Equal(common.Hash{}, db.GetState(address, key1)) suite.Require().Equal(common.Hash{}, db.GetCommittedState(address, key1)) @@ -468,7 +466,7 @@ func (suite *StateDBTestSuite) TestAccessList() { func (suite *StateDBTestSuite) TestLog() { txHash := common.BytesToHash([]byte("tx")) // use a non-default tx config - txConfig := types.NewTxConfig( + txConfig := statedb.NewTxConfig( blockHash, txHash, 1, 1, diff --git a/x/evm/types/statedb.go b/x/evm/types/statedb.go deleted file mode 100644 index 866cfd3441..0000000000 --- a/x/evm/types/statedb.go +++ /dev/null @@ -1,61 +0,0 @@ -package types - -import ( - "bytes" - "math/big" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto" -) - -var emptyCodeHash = crypto.Keccak256(nil) - -// StateDBAccount is the Ethereum consensus representation of accounts. -// These objects are stored in the storage of auth module. -type StateDBAccount struct { - Nonce uint64 - Balance *big.Int - CodeHash []byte -} - -// NewEmptyAccount returns an empty account. -func NewEmptyAccount() *StateDBAccount { - return &StateDBAccount{ - Balance: new(big.Int), - CodeHash: emptyCodeHash, - } -} - -// IsContract returns if the account contains contract code. -func (acct StateDBAccount) IsContract() bool { - return !bytes.Equal(acct.CodeHash, emptyCodeHash) -} - -// TxConfig encapulates the readonly information of current tx for `StateDB`. -type TxConfig struct { - BlockHash common.Hash // hash of current block - TxHash common.Hash // hash of current tx - TxIndex uint // the index of current transaction - LogIndex uint // the index of next log within current block -} - -// NewTxConfig returns a TxConfig -func NewTxConfig(bhash, thash common.Hash, txIndex, logIndex uint) TxConfig { - return TxConfig{ - BlockHash: bhash, - TxHash: thash, - TxIndex: txIndex, - LogIndex: logIndex, - } -} - -// NewEmptyTxConfig construct an empty TxConfig, -// used in context where there's no transaction, e.g. `eth_call`/`eth_estimateGas`. -func NewEmptyTxConfig(bhash common.Hash) TxConfig { - return TxConfig{ - BlockHash: bhash, - TxHash: common.Hash{}, - TxIndex: 0, - LogIndex: 0, - } -} diff --git a/x/evm/vm/interface.go b/x/evm/vm/interface.go index 9e5d05e6d4..f1a6f4f707 100644 --- a/x/evm/vm/interface.go +++ b/x/evm/vm/interface.go @@ -18,11 +18,7 @@ package vm import ( "math/big" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/evmos/ethermint/x/evm/types" - "github.com/ethereum/go-ethereum/common" - ethtypes "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/params" "github.com/holiman/uint256" @@ -83,43 +79,3 @@ type Constructor func( config vm.Config, customPrecompiles PrecompiledContracts, ) EVM - -// StateDBKeeper provide underlying storage of StateDB -type StateDBKeeper interface { - // Read methods - GetAccount(ctx sdk.Context, addr common.Address) *types.StateDBAccount - GetState(ctx sdk.Context, addr common.Address, key common.Hash) common.Hash - GetCode(ctx sdk.Context, codeHash common.Hash) []byte - // the callback returns false to break early - ForEachStorage(ctx sdk.Context, addr common.Address, cb func(key, value common.Hash) bool) - - // Write methods, only called by `StateDB.Commit()` - SetAccount(ctx sdk.Context, addr common.Address, account types.StateDBAccount) error - SetState(ctx sdk.Context, addr common.Address, key common.Hash, value []byte) - SetCode(ctx sdk.Context, codeHash []byte, code []byte) - DeleteAccount(ctx sdk.Context, addr common.Address) error -} - -type StateDB interface { - vm.StateDB - - Keeper() StateDBKeeper - - // Additional methods required by x/evm Keeper - Commit() error - Logs() []*ethtypes.Log -} - -// TxConfig provides readonly information of current tx for `StateDB`. -type TxConfig interface { - BlockHash() common.Hash // hash of current block - TxHash() common.Hash // hash of current tx - TxIndex() uint // the index of current transaction - LogIndex() uint // the index of next log within current block -} - -type StateDBConstructor func( - ctx sdk.Context, - keeper StateDBKeeper, - txConfig types.TxConfig, -) StateDB