From bf95e9a0103d9051fdccfad485b38a9aa08ef4fb Mon Sep 17 00:00:00 2001 From: VictorTrustyDev Date: Tue, 3 Sep 2024 02:59:50 +0700 Subject: [PATCH 1/6] use authtypes.BaseAccount instead of EthAccount --- app/app.go | 2 +- client/testnet.go | 12 +- cmd/evmd/testnet.go | 11 +- ibc/testing/chain.go | 14 +- .../types/chain_app_imp_init.go | 23 +- proto/ethermint/evm/v1/query.proto | 3 +- proto/ethermint/types/v1/account.proto | 25 -- .../eth_rpc_it_suite/eth_api_account_test.go | 8 +- testutil/network/network.go | 7 +- types/account.go | 82 ---- types/account.pb.go | 377 ------------------ types/account_test.go | 58 --- types/codec.go | 9 - x/evm/genesis.go | 40 +- x/evm/genesis_test.go | 78 ++-- x/evm/handler_test.go | 6 +- x/evm/keeper/keeper.go | 8 +- x/evm/keeper/keeper_test.go | 14 +- x/evm/keeper/setup_test.go | 6 +- x/evm/keeper/statedb.go | 89 ++++- x/evm/keeper/statedb_test.go | 18 +- x/evm/statedb/state_object.go | 14 +- x/evm/types/key.go | 8 +- x/evm/types/utils.go | 6 + x/feemarket/keeper/utils_test.go | 12 +- 25 files changed, 204 insertions(+), 726 deletions(-) delete mode 100644 proto/ethermint/types/v1/account.proto delete mode 100644 types/account.go delete mode 100644 types/account.pb.go delete mode 100644 types/account_test.go diff --git a/app/app.go b/app/app.go index 463015be6e..d106aa63de 100644 --- a/app/app.go +++ b/app/app.go @@ -376,7 +376,7 @@ func NewEvermint( // use custom Ethermint account for contracts chainApp.AccountKeeper = authkeeper.NewAccountKeeper( - appCodec, keys[authtypes.StoreKey], evertypes.ProtoAccount, maccPerms, sdk.GetConfig().GetBech32AccountAddrPrefix(), authAddr, + appCodec, keys[authtypes.StoreKey], authtypes.ProtoBaseAccount, maccPerms, sdk.GetConfig().GetBech32AccountAddrPrefix(), authAddr, ) chainApp.BankKeeper = bankkeeper.NewBaseKeeper( appCodec, keys[banktypes.StoreKey], chainApp.AccountKeeper, chainApp.BlockedAddrs(), authAddr, diff --git a/client/testnet.go b/client/testnet.go index 8d67e987c2..1aca2ae75d 100644 --- a/client/testnet.go +++ b/client/testnet.go @@ -15,8 +15,6 @@ import ( "path/filepath" "strings" - "github.com/ethereum/go-ethereum/common" - tmconfig "github.com/cometbft/cometbft/config" tmrand "github.com/cometbft/cometbft/libs/rand" "github.com/cometbft/cometbft/types" @@ -341,10 +339,7 @@ func initTestnetFiles( } genBalances = append(genBalances, banktypes.Balance{Address: addr.String(), Coins: coins.Sort()}) - genAccounts = append(genAccounts, &evertypes.EthAccount{ - BaseAccount: authtypes.NewBaseAccount(addr, nil, 0, 0), - CodeHash: common.BytesToHash(evmtypes.EmptyCodeHash).Hex(), - }) + genAccounts = append(genAccounts, authtypes.NewBaseAccount(addr, nil, 0, 0)) valTokens := sdk.TokensFromConsensusPower(100, evertypes.PowerReduction) createValMsg, err := stakingtypes.NewMsgCreateValidator( @@ -417,10 +412,7 @@ func initTestnetFiles( sdk.NewCoin(constants.BaseDenom, sdk.TokensFromConsensusPower(1000, evertypes.PowerReduction)), } genBalances = append(genBalances, banktypes.Balance{Address: normalAccountAddr.String(), Coins: coins.Sort()}) - genAccounts = append(genAccounts, &evertypes.EthAccount{ - BaseAccount: authtypes.NewBaseAccount(normalAccountAddr, nil, 0, 0), - CodeHash: common.BytesToHash(evmtypes.EmptyCodeHash).Hex(), - }) + genAccounts = append(genAccounts, authtypes.NewBaseAccount(normalAccountAddr, nil, 0, 0)) } if err := initGenFiles(clientCtx, mbm, args.chainID, constants.BaseDenom, genAccounts, genBalances, genFiles, args.numValidators); err != nil { diff --git a/cmd/evmd/testnet.go b/cmd/evmd/testnet.go index 2fb31cd517..631e8c9773 100644 --- a/cmd/evmd/testnet.go +++ b/cmd/evmd/testnet.go @@ -13,7 +13,6 @@ import ( "github.com/cometbft/cometbft/types" tmtime "github.com/cometbft/cometbft/types/time" clientconfig "github.com/cosmos/cosmos-sdk/client/config" - "github.com/ethereum/go-ethereum/common" "github.com/spf13/cobra" "github.com/spf13/viper" "net" @@ -334,10 +333,7 @@ func initTestnetFiles( } genBalances = append(genBalances, banktypes.Balance{Address: addr.String(), Coins: coins.Sort()}) - genAccounts = append(genAccounts, &evertypes.EthAccount{ - BaseAccount: authtypes.NewBaseAccount(addr, nil, 0, 0), - CodeHash: common.BytesToHash(evmtypes.EmptyCodeHash).Hex(), - }) + genAccounts = append(genAccounts, authtypes.NewBaseAccount(addr, nil, 0, 0)) valTokens := sdk.TokensFromConsensusPower(100, evertypes.PowerReduction) createValMsg, err := stakingtypes.NewMsgCreateValidator( @@ -412,10 +408,7 @@ func initTestnetFiles( sdk.NewCoin(constants.BaseDenom, sdk.TokensFromConsensusPower(1000, evertypes.PowerReduction)), } genBalances = append(genBalances, banktypes.Balance{Address: normalAccountAddr.String(), Coins: coins.Sort()}) - genAccounts = append(genAccounts, &evertypes.EthAccount{ - BaseAccount: authtypes.NewBaseAccount(normalAccountAddr, nil, 0, 0), - CodeHash: common.BytesToHash(evmtypes.EmptyCodeHash).Hex(), - }) + genAccounts = append(genAccounts, authtypes.NewBaseAccount(normalAccountAddr, nil, 0, 0)) } if err := initGenFiles(clientCtx, mbm, args.chainID, constants.BaseDenom, genAccounts, genBalances, genFiles, args.numValidators); err != nil { diff --git a/ibc/testing/chain.go b/ibc/testing/chain.go index a4b44412f3..0264f42c31 100644 --- a/ibc/testing/chain.go +++ b/ibc/testing/chain.go @@ -6,8 +6,6 @@ import ( "github.com/stretchr/testify/require" - "github.com/ethereum/go-ethereum/common" - sdk "github.com/cosmos/cosmos-sdk/types" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" @@ -21,7 +19,6 @@ import ( "github.com/EscanBE/evermint/v12/crypto/ethsecp256k1" evertypes "github.com/EscanBE/evermint/v12/types" - evmtypes "github.com/EscanBE/evermint/v12/x/evm/types" ) // ChainIDPrefix defines the default chain ID prefix for our test chains @@ -59,19 +56,14 @@ func NewTestChain(t *testing.T, coord *ibcgotesting.Coordinator, chainID string) baseAcc := authtypes.NewBaseAccount(senderPrivKey.PubKey().Address().Bytes(), senderPrivKey.PubKey(), 0, 0) - acc := &evertypes.EthAccount{ - BaseAccount: baseAcc, - CodeHash: common.BytesToHash(evmtypes.EmptyCodeHash).Hex(), - } - amount := sdk.TokensFromConsensusPower(1, evertypes.PowerReduction) balance := banktypes.Balance{ - Address: acc.GetAddress().String(), + Address: baseAcc.GetAddress().String(), Coins: sdk.NewCoins(sdk.NewCoin(constants.BaseDenom, amount)), } - app := SetupWithGenesisValSet(t, valSet, []authtypes.GenesisAccount{acc}, chainID, balance) + app := SetupWithGenesisValSet(t, valSet, []authtypes.GenesisAccount{baseAcc}, chainID, balance) // create current header and call begin block header := tmproto.Header{ @@ -95,7 +87,7 @@ func NewTestChain(t *testing.T, coord *ibcgotesting.Coordinator, chainID string) Vals: valSet, Signers: signers, SenderPrivKey: senderPrivKey, - SenderAccount: acc, + SenderAccount: baseAcc, NextVals: valSet, } diff --git a/integration_test_util/types/chain_app_imp_init.go b/integration_test_util/types/chain_app_imp_init.go index fc9315a560..5ed00bba19 100644 --- a/integration_test_util/types/chain_app_imp_init.go +++ b/integration_test_util/types/chain_app_imp_init.go @@ -11,7 +11,6 @@ import ( chainapp "github.com/EscanBE/evermint/v12/app" "github.com/EscanBE/evermint/v12/constants" itutilutils "github.com/EscanBE/evermint/v12/integration_test_util/utils" - etherminttypes "github.com/EscanBE/evermint/v12/types" erc20types "github.com/EscanBE/evermint/v12/x/erc20/types" evmtypes "github.com/EscanBE/evermint/v12/x/evm/types" feemarkettypes "github.com/EscanBE/evermint/v12/x/feemarket/types" @@ -33,7 +32,6 @@ import ( minttypes "github.com/cosmos/cosmos-sdk/x/mint/types" slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - "github.com/ethereum/go-ethereum/common" "strings" "time" ) @@ -84,10 +82,7 @@ func NewChainApp(chainCfg ChainConfig, disableTendermint bool, testConfig TestCo var genesisBalances []banktypes.Balance var signingInfos []slashingtypes.SigningInfo for i, account := range append(validatorAccounts, walletAccounts...) { - acc := ðerminttypes.EthAccount{ - BaseAccount: authtypes.NewBaseAccount(account.GetCosmosAddress(), account.GetPubKey(), uint64(i), 0), - CodeHash: common.BytesToHash(evmtypes.EmptyCodeHash).Hex(), - } + acc := authtypes.NewBaseAccount(account.GetCosmosAddress(), account.GetPubKey(), uint64(i), 0) switch account.Type { case TestAccountTypeValidator: @@ -121,14 +116,14 @@ func NewChainApp(chainCfg ChainConfig, disableTendermint bool, testConfig TestCo } app := chainapp.NewEvermint( - logger, // logger - db, // db - nil, // trace store - true, // load latest - map[int64]bool{}, // skipUpgradeHeights - defaultNodeHome, // homePath - 0, // invCheckPeriod - encCfg, // encodingConfig + logger, // logger + db, // db + nil, // trace store + true, // load latest + map[int64]bool{}, // skipUpgradeHeights + defaultNodeHome, // homePath + 0, // invCheckPeriod + encCfg, // encodingConfig simtestutil.NewAppOptionsWithFlagHome(defaultNodeHome), // appOpts baseapp.SetChainID(chainCfg.CosmosChainId), // baseAppOptions ) diff --git a/proto/ethermint/evm/v1/query.proto b/proto/ethermint/evm/v1/query.proto index 6931206400..12a3107430 100644 --- a/proto/ethermint/evm/v1/query.proto +++ b/proto/ethermint/evm/v1/query.proto @@ -28,8 +28,7 @@ service Query { option (google.api.http).get = "/evmos/evm/v1/validator_account/{cons_address}"; } - // Balance queries the balance of a the EVM denomination for a single - // EthAccount. + // Balance queries the balance of a the EVM denomination for a single account. rpc Balance(QueryBalanceRequest) returns (QueryBalanceResponse) { option (google.api.http).get = "/evmos/evm/v1/balances/{address}"; } diff --git a/proto/ethermint/types/v1/account.proto b/proto/ethermint/types/v1/account.proto deleted file mode 100644 index 1c2a7436ed..0000000000 --- a/proto/ethermint/types/v1/account.proto +++ /dev/null @@ -1,25 +0,0 @@ -syntax = "proto3"; -package ethermint.types.v1; - -import "cosmos/auth/v1beta1/auth.proto"; -import "cosmos_proto/cosmos.proto"; -import "gogoproto/gogo.proto"; - -option go_package = "github.com/EscanBE/evermint/v12/types"; - -// EthAccount implements the authtypes.AccountI interface and embeds an -// authtypes.BaseAccount type. It is compatible with the auth AccountKeeper. -message EthAccount { - option (gogoproto.goproto_getters) = false; - option (gogoproto.goproto_stringer) = false; - option (gogoproto.equal) = false; - - option (cosmos_proto.implements_interface) = "github.com/cosmos/cosmos-sdk/x/auth/types.AccountI"; - - // base_account is an authtypes.BaseAccount - cosmos.auth.v1beta1.BaseAccount base_account = 1 - [(gogoproto.embed) = true, (gogoproto.moretags) = "yaml:\"base_account\""]; - - // code_hash is the hash calculated from the code contents - string code_hash = 2 [(gogoproto.moretags) = "yaml:\"code_hash\""]; -} diff --git a/rpc/namespaces/ethereum/eth/eth_rpc_it_suite/eth_api_account_test.go b/rpc/namespaces/ethereum/eth/eth_rpc_it_suite/eth_api_account_test.go index ce606026f9..abdf3bfde3 100644 --- a/rpc/namespaces/ethereum/eth/eth_rpc_it_suite/eth_api_account_test.go +++ b/rpc/namespaces/ethereum/eth/eth_rpc_it_suite/eth_api_account_test.go @@ -5,7 +5,8 @@ import ( "fmt" "github.com/EscanBE/evermint/v12/integration_test_util" rpctypes "github.com/EscanBE/evermint/v12/rpc/types" - etherminttypes "github.com/EscanBE/evermint/v12/types" + "github.com/EscanBE/evermint/v12/x/evm/types" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "math/big" @@ -248,10 +249,11 @@ func (suite *EthRpcTestSuite) Test_GetCode() { accountI := suite.App().AccountKeeper().GetAccount(suite.Ctx(), contractAddr.Bytes()) suite.Require().NotNil(accountI) - contractAccount, ok := accountI.(*etherminttypes.EthAccount) + _, ok := accountI.(*authtypes.BaseAccount) suite.Require().True(ok) - codeHash := common.HexToHash(contractAccount.CodeHash) + codeHash := suite.App().EvmKeeper().GetCodeHash(suite.Ctx(), contractAddr.Bytes()) + suite.Require().False(types.IsEmptyCodeHash(codeHash)) code := suite.App().EvmKeeper().GetCode(suite.Ctx(), codeHash) suite.Require().NotEmptyf(code, "not found code for contract %s", contractAddr.String()) diff --git a/testutil/network/network.go b/testutil/network/network.go index 59e9da2f54..311c1dce46 100644 --- a/testutil/network/network.go +++ b/testutil/network/network.go @@ -25,7 +25,6 @@ import ( tmrand "github.com/cometbft/cometbft/libs/rand" "github.com/cometbft/cometbft/node" tmclient "github.com/cometbft/cometbft/rpc/client" - "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/ethclient" "github.com/spf13/cobra" "google.golang.org/grpc" @@ -56,7 +55,6 @@ import ( "github.com/EscanBE/evermint/v12/encoding" "github.com/EscanBE/evermint/v12/server/config" evertypes "github.com/EscanBE/evermint/v12/types" - evmtypes "github.com/EscanBE/evermint/v12/x/evm/types" ) // package-wide network lock to only allow one test network at a time @@ -414,10 +412,7 @@ func New(l Logger, baseDir string, cfg Config) (*Network, error) { genFiles = append(genFiles, tmCfg.GenesisFile()) genBalances = append(genBalances, banktypes.Balance{Address: addr.String(), Coins: balances.Sort()}) - genAccounts = append(genAccounts, &evertypes.EthAccount{ - BaseAccount: authtypes.NewBaseAccount(addr, nil, 0, 0), - CodeHash: common.BytesToHash(evmtypes.EmptyCodeHash).Hex(), - }) + genAccounts = append(genAccounts, authtypes.NewBaseAccount(addr, nil, 0, 0)) commission, err := sdk.NewDecFromStr("0.5") if err != nil { diff --git a/types/account.go b/types/account.go deleted file mode 100644 index e0719f8f99..0000000000 --- a/types/account.go +++ /dev/null @@ -1,82 +0,0 @@ -package types - -import ( - "bytes" - - codectypes "github.com/cosmos/cosmos-sdk/codec/types" - authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto" -) - -var ( - _ authtypes.AccountI = (*EthAccount)(nil) - _ EthAccountI = (*EthAccount)(nil) - _ authtypes.GenesisAccount = (*EthAccount)(nil) - _ codectypes.UnpackInterfacesMessage = (*EthAccount)(nil) -) - -var emptyCodeHash = crypto.Keccak256(nil) - -const ( - // AccountTypeEOA defines the type for externally owned accounts (EOAs) - AccountTypeEOA = int8(iota + 1) - // AccountTypeContract defines the type for contract accounts - AccountTypeContract -) - -// EthAccountI represents the interface of an EVM compatible account -type EthAccountI interface { - authtypes.AccountI - // EthAddress returns the ethereum Address representation of the AccAddress - EthAddress() common.Address - // GetCodeHash returns code hash is the keccak256 hash of the contract code (if any) - GetCodeHash() common.Hash - // SetCodeHash sets the code hash to the account fields - SetCodeHash(code common.Hash) error - // Type returns the type of Ethereum Account (EOA or Contract) - Type() int8 -} - -// ---------------------------------------------------------------------------- -// Main account type -// ---------------------------------------------------------------------------- - -// ProtoAccount defines the prototype function for BaseAccount used for an -// AccountKeeper. -func ProtoAccount() authtypes.AccountI { - return &EthAccount{ - BaseAccount: &authtypes.BaseAccount{}, - CodeHash: common.BytesToHash(emptyCodeHash).String(), - } -} - -// GetBaseAccount returns base account. -func (acc EthAccount) GetBaseAccount() *authtypes.BaseAccount { - return acc.BaseAccount -} - -// EthAddress returns the account address ethereum format. -func (acc EthAccount) EthAddress() common.Address { - return common.BytesToAddress(acc.GetAddress().Bytes()) -} - -// GetCodeHash returns the account code hash in byte format -func (acc EthAccount) GetCodeHash() common.Hash { - return common.HexToHash(acc.CodeHash) -} - -// SetCodeHash sets the account code hash to the EthAccount fields -func (acc *EthAccount) SetCodeHash(codeHash common.Hash) error { - acc.CodeHash = codeHash.Hex() - return nil -} - -// Type returns the type of Ethereum Account (EOA or Contract) -func (acc EthAccount) Type() int8 { - if bytes.Equal(emptyCodeHash, common.HexToHash(acc.CodeHash).Bytes()) { - return AccountTypeEOA - } - return AccountTypeContract -} diff --git a/types/account.pb.go b/types/account.pb.go deleted file mode 100644 index 2b2f567949..0000000000 --- a/types/account.pb.go +++ /dev/null @@ -1,377 +0,0 @@ -// Code generated by protoc-gen-gogo. DO NOT EDIT. -// source: ethermint/types/v1/account.proto - -package types - -import ( - fmt "fmt" - _ "github.com/cosmos/cosmos-proto" - types "github.com/cosmos/cosmos-sdk/x/auth/types" - _ "github.com/cosmos/gogoproto/gogoproto" - proto "github.com/cosmos/gogoproto/proto" - io "io" - math "math" - math_bits "math/bits" -) - -// Reference imports to suppress errors if they are not otherwise used. -var _ = proto.Marshal -var _ = fmt.Errorf -var _ = math.Inf - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the proto package it is being compiled against. -// A compilation error at this line likely means your copy of the -// proto package needs to be updated. -const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package - -// EthAccount implements the authtypes.AccountI interface and embeds an -// authtypes.BaseAccount type. It is compatible with the auth AccountKeeper. -type EthAccount struct { - // base_account is an authtypes.BaseAccount - *types.BaseAccount `protobuf:"bytes,1,opt,name=base_account,json=baseAccount,proto3,embedded=base_account" json:"base_account,omitempty" yaml:"base_account"` - // code_hash is the hash calculated from the code contents - CodeHash string `protobuf:"bytes,2,opt,name=code_hash,json=codeHash,proto3" json:"code_hash,omitempty" yaml:"code_hash"` -} - -func (m *EthAccount) Reset() { *m = EthAccount{} } -func (*EthAccount) ProtoMessage() {} -func (*EthAccount) Descriptor() ([]byte, []int) { - return fileDescriptor_4edc057d42a619ef, []int{0} -} -func (m *EthAccount) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *EthAccount) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_EthAccount.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *EthAccount) XXX_Merge(src proto.Message) { - xxx_messageInfo_EthAccount.Merge(m, src) -} -func (m *EthAccount) XXX_Size() int { - return m.Size() -} -func (m *EthAccount) XXX_DiscardUnknown() { - xxx_messageInfo_EthAccount.DiscardUnknown(m) -} - -var xxx_messageInfo_EthAccount proto.InternalMessageInfo - -func init() { - proto.RegisterType((*EthAccount)(nil), "ethermint.types.v1.EthAccount") -} - -func init() { proto.RegisterFile("ethermint/types/v1/account.proto", fileDescriptor_4edc057d42a619ef) } - -var fileDescriptor_4edc057d42a619ef = []byte{ - // 322 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x4c, 0x51, 0xbf, 0x4e, 0x3a, 0x31, - 0x1c, 0x6f, 0x7f, 0xc3, 0x2f, 0x72, 0x38, 0x98, 0x93, 0x01, 0x31, 0x69, 0x2f, 0x97, 0x98, 0xb0, - 0xd0, 0xa6, 0xb8, 0xb1, 0x18, 0x9b, 0x90, 0xe8, 0xca, 0xe8, 0x82, 0xbd, 0xd2, 0x50, 0xa2, 0x47, - 0x09, 0x2d, 0x17, 0x79, 0x03, 0x47, 0x47, 0x47, 0x1e, 0xc2, 0x87, 0x30, 0x4e, 0x8c, 0x4e, 0xc4, - 0x40, 0x4c, 0x9c, 0x79, 0x02, 0xc3, 0xb5, 0x41, 0xa6, 0x7e, 0xff, 0x7c, 0xfe, 0xb4, 0x9f, 0x46, - 0x89, 0x72, 0x5a, 0x4d, 0xf3, 0xd1, 0xd8, 0x51, 0x37, 0x9f, 0x28, 0x4b, 0x0b, 0x46, 0x85, 0x94, - 0x66, 0x36, 0x76, 0x64, 0x32, 0x35, 0xce, 0xc4, 0xf1, 0x1e, 0x41, 0x4a, 0x04, 0x29, 0x58, 0x03, - 0x49, 0x63, 0x73, 0x63, 0xa9, 0x98, 0x39, 0x4d, 0x0b, 0x96, 0x29, 0x27, 0x58, 0xd9, 0x78, 0x4e, - 0xe3, 0xcc, 0xef, 0xfb, 0x65, 0x47, 0x7d, 0x13, 0x56, 0xb5, 0xa1, 0x19, 0x1a, 0x3f, 0xdf, 0x55, - 0x7e, 0x9a, 0x7e, 0xc3, 0x28, 0xea, 0x3a, 0x7d, 0xed, 0x9d, 0xe3, 0xfb, 0xe8, 0x38, 0x13, 0x56, - 0xf5, 0xc3, 0x4d, 0xea, 0x30, 0x81, 0xcd, 0x6a, 0x3b, 0x21, 0x41, 0xa9, 0x74, 0x0a, 0xb6, 0x84, - 0x0b, 0xab, 0x02, 0x8f, 0x9f, 0x2f, 0x57, 0x18, 0x6e, 0x57, 0xf8, 0x74, 0x2e, 0xf2, 0xc7, 0x4e, - 0x7a, 0xa8, 0x91, 0xf6, 0xaa, 0xd9, 0x1f, 0x32, 0x66, 0x51, 0x45, 0x9a, 0x81, 0xea, 0x6b, 0x61, - 0x75, 0xfd, 0x5f, 0x02, 0x9b, 0x15, 0x5e, 0xdb, 0xae, 0xf0, 0x89, 0x27, 0xee, 0x57, 0x69, 0xef, - 0x68, 0x57, 0xdf, 0x08, 0xab, 0x3b, 0xfc, 0x79, 0x81, 0xc1, 0xeb, 0x02, 0x83, 0x9f, 0x05, 0x06, - 0x1f, 0x6f, 0xad, 0xf6, 0x70, 0xe4, 0xf4, 0x2c, 0x23, 0xd2, 0xe4, 0xe1, 0x89, 0xe1, 0x68, 0xd9, - 0xc1, 0x03, 0x7d, 0xf2, 0xe1, 0xf8, 0xc8, 0x82, 0xeb, 0x2d, 0xbf, 0x7a, 0x5f, 0x23, 0xb8, 0x5c, - 0x23, 0xf8, 0xb5, 0x46, 0xf0, 0x65, 0x83, 0xc0, 0x72, 0x83, 0xc0, 0xe7, 0x06, 0x81, 0xbb, 0x8b, - 0x03, 0xb5, 0xae, 0x95, 0x62, 0xcc, 0xbb, 0x54, 0x15, 0xe1, 0x6b, 0x0a, 0xd6, 0xf6, 0x4a, 0xd9, - 0xff, 0x32, 0xaf, 0xcb, 0xdf, 0x00, 0x00, 0x00, 0xff, 0xff, 0x6f, 0xff, 0xc5, 0x26, 0xb8, 0x01, - 0x00, 0x00, -} - -func (m *EthAccount) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *EthAccount) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *EthAccount) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if len(m.CodeHash) > 0 { - i -= len(m.CodeHash) - copy(dAtA[i:], m.CodeHash) - i = encodeVarintAccount(dAtA, i, uint64(len(m.CodeHash))) - i-- - dAtA[i] = 0x12 - } - if m.BaseAccount != nil { - { - size, err := m.BaseAccount.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintAccount(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - -func encodeVarintAccount(dAtA []byte, offset int, v uint64) int { - offset -= sovAccount(v) - base := offset - for v >= 1<<7 { - dAtA[offset] = uint8(v&0x7f | 0x80) - v >>= 7 - offset++ - } - dAtA[offset] = uint8(v) - return base -} -func (m *EthAccount) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.BaseAccount != nil { - l = m.BaseAccount.Size() - n += 1 + l + sovAccount(uint64(l)) - } - l = len(m.CodeHash) - if l > 0 { - n += 1 + l + sovAccount(uint64(l)) - } - return n -} - -func sovAccount(x uint64) (n int) { - return (math_bits.Len64(x|1) + 6) / 7 -} -func sozAccount(x uint64) (n int) { - return sovAccount(uint64((x << 1) ^ uint64((int64(x) >> 63)))) -} -func (m *EthAccount) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowAccount - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: EthAccount: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: EthAccount: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field BaseAccount", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowAccount - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthAccount - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthAccount - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if m.BaseAccount == nil { - m.BaseAccount = &types.BaseAccount{} - } - if err := m.BaseAccount.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field CodeHash", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowAccount - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthAccount - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthAccount - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.CodeHash = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipAccount(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthAccount - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func skipAccount(dAtA []byte) (n int, err error) { - l := len(dAtA) - iNdEx := 0 - depth := 0 - for iNdEx < l { - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowAccount - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - wireType := int(wire & 0x7) - switch wireType { - case 0: - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowAccount - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - iNdEx++ - if dAtA[iNdEx-1] < 0x80 { - break - } - } - case 1: - iNdEx += 8 - case 2: - var length int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowAccount - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - length |= (int(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - if length < 0 { - return 0, ErrInvalidLengthAccount - } - iNdEx += length - case 3: - depth++ - case 4: - if depth == 0 { - return 0, ErrUnexpectedEndOfGroupAccount - } - depth-- - case 5: - iNdEx += 4 - default: - return 0, fmt.Errorf("proto: illegal wireType %d", wireType) - } - if iNdEx < 0 { - return 0, ErrInvalidLengthAccount - } - if depth == 0 { - return iNdEx, nil - } - } - return 0, io.ErrUnexpectedEOF -} - -var ( - ErrInvalidLengthAccount = fmt.Errorf("proto: negative length found during unmarshaling") - ErrIntOverflowAccount = fmt.Errorf("proto: integer overflow") - ErrUnexpectedEndOfGroupAccount = fmt.Errorf("proto: unexpected end of group") -) diff --git a/types/account_test.go b/types/account_test.go deleted file mode 100644 index 0d5ecc56dd..0000000000 --- a/types/account_test.go +++ /dev/null @@ -1,58 +0,0 @@ -package types_test - -import ( - "testing" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto" - "github.com/stretchr/testify/suite" - - "github.com/cosmos/cosmos-sdk/codec" - codectypes "github.com/cosmos/cosmos-sdk/codec/types" - sdk "github.com/cosmos/cosmos-sdk/types" - authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" - - cryptocodec "github.com/EscanBE/evermint/v12/crypto/codec" - "github.com/EscanBE/evermint/v12/crypto/ethsecp256k1" - encodingcodec "github.com/EscanBE/evermint/v12/encoding/codec" - "github.com/EscanBE/evermint/v12/types" -) - -func init() { - amino := codec.NewLegacyAmino() - cryptocodec.RegisterCrypto(amino) -} - -type AccountTestSuite struct { - suite.Suite - - account *types.EthAccount - cdc codec.JSONCodec -} - -func (suite *AccountTestSuite) SetupTest() { - privKey, err := ethsecp256k1.GenerateKey() - suite.Require().NoError(err) - pubKey := privKey.PubKey() - addr := sdk.AccAddress(pubKey.Address()) - baseAcc := authtypes.NewBaseAccount(addr, pubKey, 10, 50) - suite.account = &types.EthAccount{ - BaseAccount: baseAcc, - CodeHash: common.Hash{}.String(), - } - - interfaceRegistry := codectypes.NewInterfaceRegistry() - encodingcodec.RegisterInterfaces(interfaceRegistry) - suite.cdc = codec.NewProtoCodec(interfaceRegistry) -} - -func TestAccountTestSuite(t *testing.T) { - suite.Run(t, new(AccountTestSuite)) -} - -func (suite *AccountTestSuite) TestAccountType() { - suite.account.CodeHash = common.BytesToHash(crypto.Keccak256(nil)).Hex() - suite.Require().Equal(types.AccountTypeEOA, suite.account.Type()) - suite.account.CodeHash = common.BytesToHash(crypto.Keccak256([]byte{1, 2, 3})).Hex() - suite.Require().Equal(types.AccountTypeContract, suite.account.Type()) -} diff --git a/types/codec.go b/types/codec.go index 287716340e..d492304d79 100644 --- a/types/codec.go +++ b/types/codec.go @@ -3,20 +3,11 @@ package types import ( codectypes "github.com/cosmos/cosmos-sdk/codec/types" "github.com/cosmos/cosmos-sdk/types/tx" - authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" ) // RegisterInterfaces registers the tendermint concrete client-related // implementations and interfaces. func RegisterInterfaces(registry codectypes.InterfaceRegistry) { - registry.RegisterImplementations( - (*authtypes.AccountI)(nil), - &EthAccount{}, - ) - registry.RegisterImplementations( - (*authtypes.GenesisAccount)(nil), - &EthAccount{}, - ) registry.RegisterImplementations( (*tx.TxExtensionOptionI)(nil), &ExtensionOptionsWeb3Tx{}, diff --git a/x/evm/genesis.go b/x/evm/genesis.go index 1a014905ff..e0444bbad8 100644 --- a/x/evm/genesis.go +++ b/x/evm/genesis.go @@ -1,7 +1,6 @@ package evm import ( - "bytes" "fmt" abci "github.com/cometbft/cometbft/abci/types" @@ -10,7 +9,6 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" - evertypes "github.com/EscanBE/evermint/v12/types" "github.com/EscanBE/evermint/v12/x/evm/keeper" "github.com/EscanBE/evermint/v12/x/evm/types" ) @@ -37,31 +35,29 @@ func InitGenesis( for _, account := range data.Accounts { address := common.HexToAddress(account.Address) accAddress := sdk.AccAddress(address.Bytes()) - // check that the EVM balance the matches the account balance + acc := accountKeeper.GetAccount(ctx, accAddress) if acc == nil { panic(fmt.Errorf("account not found for address %s", account.Address)) } - - ethAcct, ok := acc.(evertypes.EthAccountI) - if !ok { + if _, isBaseAccount := acc.(*authtypes.BaseAccount); !isBaseAccount { panic( - fmt.Errorf("account %s must be an EthAccount interface, got %T", - account.Address, acc, + fmt.Errorf("account %s must be %T, got %T", + account.Address, (*authtypes.BaseAccount)(nil), acc, ), ) } + code := common.Hex2Bytes(account.Code) codeHash := crypto.Keccak256Hash(code) - // we ignore the empty Code hash checking, see ethermint PR#1234 - if len(account.Code) != 0 && !bytes.Equal(ethAcct.GetCodeHash().Bytes(), codeHash.Bytes()) { - s := "the evm state code doesn't match with the codehash\n" - panic(fmt.Sprintf("%s account: %s , evm state codehash: %v, ethAccount codehash: %v, evm state code: %s\n", - s, account.Address, codeHash, ethAcct.GetCodeHash(), account.Code)) + if !types.IsEmptyCodeHash(codeHash) { + k.SetCodeHash(ctx, address, codeHash) } - k.SetCode(ctx, codeHash.Bytes(), code) + if len(code) > 0 { + k.SetCode(ctx, codeHash.Bytes(), code) + } for _, storage := range account.Storage { k.SetState(ctx, address, common.HexToHash(storage.Key), common.HexToHash(storage.Value).Bytes()) @@ -75,19 +71,19 @@ func InitGenesis( func ExportGenesis(ctx sdk.Context, k *keeper.Keeper, ak types.AccountKeeper) *types.GenesisState { var ethGenAccounts []types.GenesisAccount ak.IterateAccounts(ctx, func(account authtypes.AccountI) bool { - ethAccount, ok := account.(evertypes.EthAccountI) - if !ok { - // ignore non EthAccounts + accAddr := account.GetAddress() + codeHash := k.GetCodeHash(ctx, accAddr) + if types.IsEmptyCodeHash(codeHash) { + // ignore non-contract accounts return false } - addr := ethAccount.EthAddress() - - storage := k.GetAccountStorage(ctx, addr) + ethAddr := common.BytesToAddress(accAddr) + storage := k.GetAccountStorage(ctx, ethAddr) genAccount := types.GenesisAccount{ - Address: addr.String(), - Code: common.Bytes2Hex(k.GetCode(ctx, ethAccount.GetCodeHash())), + Address: ethAddr.String(), + Code: common.Bytes2Hex(k.GetCode(ctx, codeHash)), Storage: storage, } diff --git a/x/evm/genesis_test.go b/x/evm/genesis_test.go index 866e5354f2..c900b25cab 100644 --- a/x/evm/genesis_test.go +++ b/x/evm/genesis_test.go @@ -1,12 +1,12 @@ package evm_test import ( + vestingtypes "github.com/cosmos/cosmos-sdk/x/auth/vesting/types" "math/big" "github.com/ethereum/go-ethereum/common" "github.com/EscanBE/evermint/v12/crypto/ethsecp256k1" - evertypes "github.com/EscanBE/evermint/v12/types" "github.com/EscanBE/evermint/v12/x/evm" "github.com/EscanBE/evermint/v12/x/evm/statedb" "github.com/EscanBE/evermint/v12/x/evm/types" @@ -28,17 +28,17 @@ func (suite *EvmTestSuite) TestInitGenesis() { expPanic bool }{ { - "default", - func() {}, - types.DefaultGenesisState(), - false, + name: "pass - default", + malleate: func() {}, + genState: types.DefaultGenesisState(), + expPanic: false, }, { - "valid account", - func() { + name: "pass - valid account", + malleate: func() { vmdb.AddBalance(address, big.NewInt(1)) }, - &types.GenesisState{ + genState: &types.GenesisState{ Params: types.DefaultParams(), Accounts: []types.GenesisAccount{ { @@ -49,12 +49,12 @@ func (suite *EvmTestSuite) TestInitGenesis() { }, }, }, - false, + expPanic: false, }, { - "account not found", - func() {}, - &types.GenesisState{ + name: "fail - account not found", + malleate: func() {}, + genState: &types.GenesisState{ Params: types.DefaultParams(), Accounts: []types.GenesisAccount{ { @@ -62,15 +62,15 @@ func (suite *EvmTestSuite) TestInitGenesis() { }, }, }, - true, + expPanic: true, }, { - "invalid account type", - func() { + name: "pass - BaseAccount", + malleate: func() { acc := authtypes.NewBaseAccountWithAddress(address.Bytes()) suite.app.AccountKeeper.SetAccount(suite.ctx, acc) }, - &types.GenesisState{ + genState: &types.GenesisState{ Params: types.DefaultParams(), Accounts: []types.GenesisAccount{ { @@ -78,33 +78,37 @@ func (suite *EvmTestSuite) TestInitGenesis() { }, }, }, - true, + expPanic: false, }, { - "invalid code hash", - func() { - acc := suite.app.AccountKeeper.NewAccountWithAddress(suite.ctx, address.Bytes()) - suite.app.AccountKeeper.SetAccount(suite.ctx, acc) + name: "fail - invalid account type", + malleate: func() { + baseVestingAccount := &vestingtypes.BaseVestingAccount{ + BaseAccount: authtypes.NewBaseAccountWithAddress(address.Bytes()), + OriginalVesting: nil, + DelegatedFree: nil, + DelegatedVesting: nil, + EndTime: suite.ctx.BlockTime().Unix() + 1000, + } + suite.app.AccountKeeper.SetAccount(suite.ctx, baseVestingAccount) }, - &types.GenesisState{ + genState: &types.GenesisState{ Params: types.DefaultParams(), Accounts: []types.GenesisAccount{ { Address: address.String(), - Code: "ffffffff", }, }, }, - true, + expPanic: true, }, { - "ignore empty account code checking", - func() { + name: "pass - ignore empty account code checking", + malleate: func() { acc := suite.app.AccountKeeper.NewAccountWithAddress(suite.ctx, address.Bytes()) - suite.app.AccountKeeper.SetAccount(suite.ctx, acc) }, - &types.GenesisState{ + genState: &types.GenesisState{ Params: types.DefaultParams(), Accounts: []types.GenesisAccount{ { @@ -113,19 +117,17 @@ func (suite *EvmTestSuite) TestInitGenesis() { }, }, }, - false, + expPanic: false, }, { - "ignore empty account code checking with non-empty codehash", - func() { - ethAcc := &evertypes.EthAccount{ - BaseAccount: authtypes.NewBaseAccount(address.Bytes(), nil, 0, 0), - CodeHash: common.BytesToHash([]byte{1, 2, 3}).Hex(), - } + name: "pass - ignore empty account code checking with non-empty code-hash", + malleate: func() { + acc := authtypes.NewBaseAccount(address.Bytes(), nil, 0, 0) + suite.app.AccountKeeper.SetAccount(suite.ctx, acc) - suite.app.AccountKeeper.SetAccount(suite.ctx, ethAcc) + suite.app.EvmKeeper.SetCodeHash(suite.ctx, address, common.BytesToHash([]byte{1, 2, 3})) }, - &types.GenesisState{ + genState: &types.GenesisState{ Params: types.DefaultParams(), Accounts: []types.GenesisAccount{ { @@ -134,7 +136,7 @@ func (suite *EvmTestSuite) TestInitGenesis() { }, }, }, - false, + expPanic: false, }, } diff --git a/x/evm/handler_test.go b/x/evm/handler_test.go index 9d6636de69..06878d873a 100644 --- a/x/evm/handler_test.go +++ b/x/evm/handler_test.go @@ -36,7 +36,6 @@ import ( "github.com/EscanBE/evermint/v12/app" "github.com/EscanBE/evermint/v12/crypto/ethsecp256k1" utiltx "github.com/EscanBE/evermint/v12/testutil/tx" - evertypes "github.com/EscanBE/evermint/v12/types" "github.com/EscanBE/evermint/v12/x/evm" "github.com/EscanBE/evermint/v12/x/evm/statedb" "github.com/EscanBE/evermint/v12/x/evm/types" @@ -147,10 +146,7 @@ func (suite *EvmTestSuite) DoSetupTest(t require.TestingT) { queryHelper := baseapp.NewQueryServerTestHelper(suite.ctx, suite.app.InterfaceRegistry()) types.RegisterQueryServer(queryHelper, suite.app.EvmKeeper) - acc := &evertypes.EthAccount{ - BaseAccount: authtypes.NewBaseAccount(sdk.AccAddress(address.Bytes()), nil, 0, 0), - CodeHash: common.BytesToHash(crypto.Keccak256(nil)).String(), - } + acc := authtypes.NewBaseAccount(address.Bytes(), nil, 0, 0) suite.app.AccountKeeper.SetAccount(suite.ctx, acc) diff --git a/x/evm/keeper/keeper.go b/x/evm/keeper/keeper.go index d085e3e7ea..ab03e52dc1 100644 --- a/x/evm/keeper/keeper.go +++ b/x/evm/keeper/keeper.go @@ -261,15 +261,9 @@ func (k *Keeper) GetAccountWithoutBalance(ctx sdk.Context, addr common.Address) return nil } - codeHash := types.EmptyCodeHash - ethAcct, ok := acct.(evertypes.EthAccountI) - if ok { - codeHash = ethAcct.GetCodeHash().Bytes() - } - return &statedb.Account{ Nonce: acct.GetSequence(), - CodeHash: codeHash, + CodeHash: k.GetCodeHash(ctx, addr.Bytes()).Bytes(), } } diff --git a/x/evm/keeper/keeper_test.go b/x/evm/keeper/keeper_test.go index e65dc33a76..8e31337546 100644 --- a/x/evm/keeper/keeper_test.go +++ b/x/evm/keeper/keeper_test.go @@ -8,7 +8,6 @@ import ( authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" - evertypes "github.com/EscanBE/evermint/v12/types" "github.com/EscanBE/evermint/v12/x/evm/keeper" "github.com/EscanBE/evermint/v12/x/evm/statedb" evmtypes "github.com/EscanBE/evermint/v12/x/evm/types" @@ -135,14 +134,19 @@ func (suite *KeeperTestSuite) TestGetAccountStorage() { tc.malleate() i := 0 suite.app.AccountKeeper.IterateAccounts(suite.ctx, func(account authtypes.AccountI) bool { - ethAccount, ok := account.(evertypes.EthAccountI) + baseAccount, ok := account.(*authtypes.BaseAccount) if !ok { - // ignore non EthAccounts + // ignore non base-account return false } - addr := ethAccount.EthAddress() - storage := suite.app.EvmKeeper.GetAccountStorage(suite.ctx, addr) + codeHash := suite.app.EvmKeeper.GetCodeHash(suite.ctx, baseAccount.GetAddress()) + if evmtypes.IsEmptyCodeHash(codeHash) { + // ignore non contract accounts + return false + } + + storage := suite.app.EvmKeeper.GetAccountStorage(suite.ctx, common.BytesToAddress(baseAccount.GetAddress())) suite.Require().Equal(tc.expRes[i], len(storage)) i++ diff --git a/x/evm/keeper/setup_test.go b/x/evm/keeper/setup_test.go index 86d5b29a80..1c20e4e9f9 100644 --- a/x/evm/keeper/setup_test.go +++ b/x/evm/keeper/setup_test.go @@ -16,7 +16,6 @@ import ( "github.com/EscanBE/evermint/v12/encoding" "github.com/EscanBE/evermint/v12/testutil" utiltx "github.com/EscanBE/evermint/v12/testutil/tx" - evertypes "github.com/EscanBE/evermint/v12/types" evmtypes "github.com/EscanBE/evermint/v12/x/evm/types" feemarkettypes "github.com/EscanBE/evermint/v12/x/feemarket/types" abci "github.com/cometbft/cometbft/abci/types" @@ -172,10 +171,7 @@ func (suite *KeeperTestSuite) SetupAppWithT(checkTx bool, t require.TestingT) { evmtypes.RegisterQueryServer(queryHelper, suite.app.EvmKeeper) suite.queryClient = evmtypes.NewQueryClient(queryHelper) - acc := &evertypes.EthAccount{ - BaseAccount: authtypes.NewBaseAccount(sdk.AccAddress(suite.address.Bytes()), nil, 0, 0), - CodeHash: common.BytesToHash(crypto.Keccak256(nil)).String(), - } + acc := authtypes.NewBaseAccount(suite.address.Bytes(), nil, 0, 0) suite.app.AccountKeeper.SetAccount(suite.ctx, acc) diff --git a/x/evm/keeper/statedb.go b/x/evm/keeper/statedb.go index 533d973094..82c5c2ba67 100644 --- a/x/evm/keeper/statedb.go +++ b/x/evm/keeper/statedb.go @@ -2,12 +2,13 @@ package keeper import ( "fmt" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + vestingtypes "github.com/cosmos/cosmos-sdk/x/auth/vesting/types" "math/big" sdkmath "cosmossdk.io/math" errorsmod "cosmossdk.io/errors" - evertypes "github.com/EscanBE/evermint/v12/types" "github.com/EscanBE/evermint/v12/x/evm/statedb" "github.com/EscanBE/evermint/v12/x/evm/types" "github.com/cosmos/cosmos-sdk/store/prefix" @@ -117,10 +118,8 @@ func (k *Keeper) SetAccount(ctx sdk.Context, addr common.Address, account stated codeHash := common.BytesToHash(account.CodeHash) - if ethAcct, ok := acct.(evertypes.EthAccountI); ok { - if err := ethAcct.SetCodeHash(codeHash); err != nil { - return err - } + if _, isBaseAccount := acct.(*authtypes.BaseAccount); isBaseAccount { + k.SetCodeHash(ctx, addr, codeHash) } k.accountKeeper.SetAccount(ctx, acct) @@ -187,10 +186,16 @@ func (k *Keeper) DeleteAccount(ctx sdk.Context, addr common.Address) error { } // NOTE: only Ethereum accounts (contracts) can be selfdestructed - _, ok := acct.(evertypes.EthAccountI) - if !ok { - return errorsmod.Wrapf(types.ErrInvalidAccount, "type %T, address %s", acct, addr) + if isNotProhibitedAccount, reason := isNotProhibitedAccountType(acct); !isNotProhibitedAccount { + return errorsmod.Wrapf(types.ErrInvalidAccount, "type %T, address %s, reason: %s", acct, addr, reason) + } + + // clear code-hash + codeHash := k.GetCodeHash(ctx, addr.Bytes()) + if types.IsEmptyCodeHash(codeHash) { + return errorsmod.Wrapf(types.ErrInvalidAccount, "type %T, address %s, not smart contract", acct, addr) } + k.DeleteCodeHash(ctx, addr.Bytes()) // clear balance if err := k.SetBalance(ctx, addr, new(big.Int)); err != nil { @@ -214,3 +219,71 @@ func (k *Keeper) DeleteAccount(ctx sdk.Context, addr common.Address) error { return nil } + +// GetCodeHash returns the code hash for the corresponding account address. +func (k *Keeper) GetCodeHash(ctx sdk.Context, addr []byte) common.Hash { + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefixCodeHash) + bz := store.Get(addr) + + var codeHash common.Hash + if len(bz) == 0 { + codeHash = common.BytesToHash(types.EmptyCodeHash) + } else { + codeHash = common.BytesToHash(bz) + } + + return codeHash +} + +// SetCodeHash sets the code hash for the given address. +func (k *Keeper) SetCodeHash(ctx sdk.Context, addr common.Address, codeHash common.Hash) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefixCodeHash) + + if types.IsEmptyCodeHash(codeHash) { + store.Delete(addr.Bytes()) + } else { + store.Set(addr.Bytes(), codeHash.Bytes()) + } +} + +// DeleteCodeHash delete the code hash for the given address. +func (k *Keeper) DeleteCodeHash(ctx sdk.Context, addr []byte) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefixCodeHash) + store.Delete(addr) +} + +// isNotProhibitedAccountType returns false if the given account is module account or vesting account +func isNotProhibitedAccountType(accI authtypes.AccountI) (notProhibited bool, explain string) { + if moduleAccount, isModuleAccount := accI.(authtypes.ModuleAccountI); isModuleAccount { + explain = fmt.Sprintf("%s is module account of %s", moduleAccount.GetAddress().String(), moduleAccount.GetName()) + return + } + + if _, isVestingAccount := accI.(*vestingtypes.BaseVestingAccount); isVestingAccount { + explain = fmt.Sprintf("%s is vesting account", accI.GetAddress().String()) + return + } + + if _, isVestingAccount := accI.(*vestingtypes.ContinuousVestingAccount); isVestingAccount { + explain = fmt.Sprintf("%s is vesting account", accI.GetAddress().String()) + return + } + + if _, isVestingAccount := accI.(*vestingtypes.DelayedVestingAccount); isVestingAccount { + explain = fmt.Sprintf("%s is vesting account", accI.GetAddress().String()) + return + } + + if _, isVestingAccount := accI.(*vestingtypes.PeriodicVestingAccount); isVestingAccount { + explain = fmt.Sprintf("%s is vesting account", accI.GetAddress().String()) + return + } + + if _, isVestingAccount := accI.(*vestingtypes.PermanentLockedAccount); isVestingAccount { + explain = fmt.Sprintf("%s is vesting account", accI.GetAddress().String()) + return + } + + notProhibited = true + return +} diff --git a/x/evm/keeper/statedb_test.go b/x/evm/keeper/statedb_test.go index 701f4c0e31..2516ddb41d 100644 --- a/x/evm/keeper/statedb_test.go +++ b/x/evm/keeper/statedb_test.go @@ -946,19 +946,19 @@ func (suite *KeeperTestSuite) TestDeleteAccount() { expErr bool }{ { - "remove address", - suite.address, - false, + name: "fail - remove address is prohibited, contract only", + addr: suite.address, + expErr: true, }, { - "remove unexistent address - returns nil error", - common.HexToAddress("unexistent_address"), - false, + name: "pass - remove non-existence address", + addr: common.HexToAddress("void"), + expErr: false, }, { - "remove deployed contract", - contractAddr, - false, + name: "pass - remove deployed contract", + addr: contractAddr, + expErr: false, }, } diff --git a/x/evm/statedb/state_object.go b/x/evm/statedb/state_object.go index ed73c67469..d18a46ddf3 100644 --- a/x/evm/statedb/state_object.go +++ b/x/evm/statedb/state_object.go @@ -2,15 +2,13 @@ package statedb import ( "bytes" + "github.com/EscanBE/evermint/v12/x/evm/types" "math/big" "sort" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto" ) -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 { @@ -23,13 +21,13 @@ type Account struct { func NewEmptyAccount() *Account { return &Account{ Balance: new(big.Int), - CodeHash: emptyCodeHash, + CodeHash: types.EmptyCodeHash, } } // IsContract returns if the account contains contract code. func (acct Account) IsContract() bool { - return !bytes.Equal(acct.CodeHash, emptyCodeHash) + return !types.IsEmptyCodeHash(common.BytesToHash(acct.CodeHash)) } // Storage represents in-memory cache/buffer of contract storage. @@ -71,7 +69,7 @@ func newObject(db *StateDB, address common.Address, account Account) *stateObjec account.Balance = new(big.Int) } if account.CodeHash == nil { - account.CodeHash = emptyCodeHash + account.CodeHash = types.EmptyCodeHash } return &stateObject{ db: db, @@ -84,7 +82,7 @@ func newObject(db *StateDB, address common.Address, account Account) *stateObjec // empty returns whether the account is considered empty. func (s *stateObject) empty() bool { - return s.account.Nonce == 0 && s.account.Balance.Sign() == 0 && bytes.Equal(s.account.CodeHash, emptyCodeHash) + return s.account.Nonce == 0 && s.account.Balance.Sign() == 0 && !s.account.IsContract() } func (s *stateObject) markSuicided() { @@ -136,7 +134,7 @@ func (s *stateObject) Code() []byte { if s.code != nil { return s.code } - if bytes.Equal(s.CodeHash(), emptyCodeHash) { + if !s.account.IsContract() { return nil } code := s.db.keeper.GetCode(s.db.ctx, common.BytesToHash(s.CodeHash())) diff --git a/x/evm/types/key.go b/x/evm/types/key.go index ec35abbdf1..0b7eaa6b57 100644 --- a/x/evm/types/key.go +++ b/x/evm/types/key.go @@ -26,6 +26,7 @@ const ( prefixCode = iota + 1 prefixStorage prefixParams + prefixCodeHash ) // prefix bytes for the EVM transient store @@ -38,9 +39,10 @@ const ( // KVStore key prefixes var ( - KeyPrefixCode = []byte{prefixCode} - KeyPrefixStorage = []byte{prefixStorage} - KeyPrefixParams = []byte{prefixParams} + KeyPrefixCode = []byte{prefixCode} + KeyPrefixStorage = []byte{prefixStorage} + KeyPrefixParams = []byte{prefixParams} + KeyPrefixCodeHash = []byte{prefixCodeHash} ) // Transient Store key prefixes diff --git a/x/evm/types/utils.go b/x/evm/types/utils.go index e3af9ff003..c64d793936 100644 --- a/x/evm/types/utils.go +++ b/x/evm/types/utils.go @@ -1,6 +1,7 @@ package types import ( + "bytes" "fmt" "math/big" @@ -86,3 +87,8 @@ func BinSearch(lo, hi uint64, executable func(uint64) (bool, *MsgEthereumTxRespo func EffectiveGasPrice(baseFee, feeCap, tipCap *big.Int) *big.Int { return math.BigMin(new(big.Int).Add(tipCap, baseFee), feeCap) } + +// IsEmptyCodeHash returns true if the given code hash is the empty code hash +func IsEmptyCodeHash(codeHash common.Hash) bool { + return bytes.Equal(codeHash.Bytes(), EmptyCodeHash) +} diff --git a/x/feemarket/keeper/utils_test.go b/x/feemarket/keeper/utils_test.go index 0771744056..2eb11532ea 100644 --- a/x/feemarket/keeper/utils_test.go +++ b/x/feemarket/keeper/utils_test.go @@ -16,18 +16,15 @@ import ( stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - "github.com/ethereum/go-ethereum/common" - ethtypes "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/crypto" - chainapp "github.com/EscanBE/evermint/v12/app" "github.com/EscanBE/evermint/v12/crypto/ethsecp256k1" "github.com/EscanBE/evermint/v12/encoding" "github.com/EscanBE/evermint/v12/testutil" utiltx "github.com/EscanBE/evermint/v12/testutil/tx" - evertypes "github.com/EscanBE/evermint/v12/types" evmtypes "github.com/EscanBE/evermint/v12/x/evm/types" "github.com/EscanBE/evermint/v12/x/feemarket/types" + "github.com/ethereum/go-ethereum/common" + ethtypes "github.com/ethereum/go-ethereum/core/types" "github.com/stretchr/testify/require" @@ -59,10 +56,7 @@ func (suite *KeeperTestSuite) SetupApp(checkTx bool) { types.RegisterQueryServer(queryHelper, suite.app.FeeMarketKeeper) suite.queryClient = types.NewQueryClient(queryHelper) - acc := &evertypes.EthAccount{ - BaseAccount: authtypes.NewBaseAccount(sdk.AccAddress(suite.address.Bytes()), nil, 0, 0), - CodeHash: common.BytesToHash(crypto.Keccak256(nil)).String(), - } + acc := authtypes.NewBaseAccount(suite.address.Bytes(), nil, 0, 0) suite.app.AccountKeeper.SetAccount(suite.ctx, acc) From b72f5da2916be9b9446191f9610fe2bf1690b695 Mon Sep 17 00:00:00 2001 From: VictorTrustyDev Date: Tue, 3 Sep 2024 03:33:38 +0700 Subject: [PATCH 2/6] refactor code --- app/ante/evm/eth.go | 20 +++++++------ app/ante/evm/eth_test.go | 4 +-- app/ante/handler_options.go | 2 +- x/evm/keeper/keeper.go | 2 +- x/evm/keeper/statedb.go | 2 +- x/evm/keeper/statedb_test.go | 54 ++++++++++++++++------------------- x/evm/statedb/mock_test.go | 10 +++---- x/evm/statedb/statedb_test.go | 5 ++-- x/evm/types/query.pb.go | 6 ++-- 9 files changed, 50 insertions(+), 55 deletions(-) diff --git a/app/ante/evm/eth.go b/app/ante/evm/eth.go index 7a9e21c5a1..9a2a03d90d 100644 --- a/app/ante/evm/eth.go +++ b/app/ante/evm/eth.go @@ -20,15 +20,17 @@ import ( ethtypes "github.com/ethereum/go-ethereum/core/types" ) -// EthAccountVerificationDecorator validates an account balance checks -type EthAccountVerificationDecorator struct { +// TODO EA: validate if vesting account has enough balance to send + +// ExternalOwnedAccountVerificationDecorator validates an account balance checks +type ExternalOwnedAccountVerificationDecorator struct { ak evmtypes.AccountKeeper evmKeeper EVMKeeper } -// NewEthAccountVerificationDecorator creates a new EthAccountVerificationDecorator -func NewEthAccountVerificationDecorator(ak evmtypes.AccountKeeper, ek EVMKeeper) EthAccountVerificationDecorator { - return EthAccountVerificationDecorator{ +// NewExternalOwnedAccountVerificationDecorator creates a new ExternalOwnedAccountVerificationDecorator +func NewExternalOwnedAccountVerificationDecorator(ak evmtypes.AccountKeeper, ek EVMKeeper) ExternalOwnedAccountVerificationDecorator { + return ExternalOwnedAccountVerificationDecorator{ ak: ak, evmKeeper: ek, } @@ -40,7 +42,7 @@ func NewEthAccountVerificationDecorator(ak evmtypes.AccountKeeper, ek EVMKeeper) // - any of the msgs is not a MsgEthereumTx // - from address is empty // - account balance is lower than the transaction cost -func (avd EthAccountVerificationDecorator) AnteHandle( +func (avd ExternalOwnedAccountVerificationDecorator) AnteHandle( ctx sdk.Context, tx sdk.Tx, simulate bool, @@ -76,8 +78,10 @@ func (avd EthAccountVerificationDecorator) AnteHandle( avd.ak.SetAccount(ctx, acc) 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) + return ctx, errorsmod.Wrapf( + errortypes.ErrInvalidType, + "the sender is not EOA: address %s, codeHash <%s>", fromAddr, acct.CodeHash, + ) } if err := keeper.CheckSenderBalance(sdkmath.NewIntFromBigInt(acct.Balance), txData); err != nil { diff --git a/app/ante/evm/eth_test.go b/app/ante/evm/eth_test.go index f56399aea3..b6159b2fd1 100644 --- a/app/ante/evm/eth_test.go +++ b/app/ante/evm/eth_test.go @@ -18,8 +18,8 @@ import ( ethtypes "github.com/ethereum/go-ethereum/core/types" ) -func (suite *AnteTestSuite) TestNewEthAccountVerificationDecorator() { - dec := ethante.NewEthAccountVerificationDecorator( +func (suite *AnteTestSuite) TestNewExternalOwnedAccountVerificationDecorator() { + dec := ethante.NewExternalOwnedAccountVerificationDecorator( suite.app.AccountKeeper, suite.app.EvmKeeper, ) diff --git a/app/ante/handler_options.go b/app/ante/handler_options.go index 23f5136fff..642ae516db 100644 --- a/app/ante/handler_options.go +++ b/app/ante/handler_options.go @@ -104,7 +104,7 @@ func newEVMAnteHandler(options HandlerOptions) sdk.AnteHandler { evmante.NewEthMinGasPriceDecorator(options.FeeMarketKeeper, options.EvmKeeper), evmante.NewEthValidateBasicDecorator(options.EvmKeeper), evmante.NewEthSigVerificationDecorator(options.EvmKeeper), - evmante.NewEthAccountVerificationDecorator(options.AccountKeeper, options.EvmKeeper), + evmante.NewExternalOwnedAccountVerificationDecorator(options.AccountKeeper, options.EvmKeeper), evmante.NewEthBasicValidationDecorator(), evmante.NewCanTransferDecorator(options.EvmKeeper), evmante.NewEthGasConsumeDecorator(options.BankKeeper, options.DistributionKeeper, options.EvmKeeper, options.StakingKeeper, options.MaxTxGasWanted), diff --git a/x/evm/keeper/keeper.go b/x/evm/keeper/keeper.go index ab03e52dc1..6b7a23cc24 100644 --- a/x/evm/keeper/keeper.go +++ b/x/evm/keeper/keeper.go @@ -267,7 +267,7 @@ func (k *Keeper) GetAccountWithoutBalance(ctx sdk.Context, addr common.Address) } } -// GetAccountOrEmpty returns empty account if not exist, returns error if it's not `EthAccount` +// GetAccountOrEmpty returns empty account if not exist func (k *Keeper) GetAccountOrEmpty(ctx sdk.Context, addr common.Address) statedb.Account { acct := k.GetAccount(ctx, addr) if acct != nil { diff --git a/x/evm/keeper/statedb.go b/x/evm/keeper/statedb.go index 82c5c2ba67..fe0a858f8b 100644 --- a/x/evm/keeper/statedb.go +++ b/x/evm/keeper/statedb.go @@ -22,7 +22,7 @@ var _ statedb.Keeper = &Keeper{} // StateDB Keeper implementation // ---------------------------------------------------------------------------- -// GetAccount returns nil if account is not exist, returns error if it's not `EthAccountI` +// GetAccount returns nil if account is not exist func (k *Keeper) GetAccount(ctx sdk.Context, addr common.Address) *statedb.Account { acct := k.GetAccountWithoutBalance(ctx, addr) if acct == nil { diff --git a/x/evm/keeper/statedb_test.go b/x/evm/keeper/statedb_test.go index 2516ddb41d..eb857ffd1b 100644 --- a/x/evm/keeper/statedb_test.go +++ b/x/evm/keeper/statedb_test.go @@ -232,22 +232,22 @@ func (suite *KeeperTestSuite) TestGetCodeHash() { malleate func(vm.StateDB) }{ { - "account not found", - utiltx.GenerateAddress(), - common.Hash{}, - func(vm.StateDB) {}, + name: "account not found", + address: utiltx.GenerateAddress(), + expHash: common.Hash{}, + malleate: func(vm.StateDB) {}, }, { - "account not EthAccount type, EmptyCodeHash", - addr, - common.BytesToHash(types.EmptyCodeHash), - func(vm.StateDB) {}, + name: "account with EmptyCodeHash", + address: addr, + expHash: common.BytesToHash(types.EmptyCodeHash), + malleate: func(vm.StateDB) {}, }, { - "existing account", - suite.address, - crypto.Keccak256Hash([]byte("codeHash")), - func(vmdb vm.StateDB) { + name: "account with non-empty code hash", + address: suite.address, + expHash: crypto.Keccak256Hash([]byte("codeHash")), + malleate: func(vmdb vm.StateDB) { vmdb.SetCode(suite.address, []byte("codeHash")) }, }, @@ -276,28 +276,22 @@ func (suite *KeeperTestSuite) TestSetCode() { isNoOp bool }{ { - "account not found", - utiltx.GenerateAddress(), - []byte("code"), - false, + name: "account not found", + address: utiltx.GenerateAddress(), + code: []byte("code"), + isNoOp: false, }, { - "account not EthAccount type", - addr, - nil, - true, - }, - { - "existing account", - suite.address, - []byte("code"), - false, + name: "existing account", + address: suite.address, + code: []byte("code"), + isNoOp: false, }, { - "existing account, code deleted from store", - suite.address, - nil, - false, + name: "existing account, code deleted from store", + address: suite.address, + code: nil, + isNoOp: false, }, } diff --git a/x/evm/statedb/mock_test.go b/x/evm/statedb/mock_test.go index cdcae6ff6c..53a3610556 100644 --- a/x/evm/statedb/mock_test.go +++ b/x/evm/statedb/mock_test.go @@ -1,20 +1,18 @@ package statedb_test import ( - "bytes" "errors" + evmtypes "github.com/EscanBE/evermint/v12/x/evm/types" "math/big" "github.com/EscanBE/evermint/v12/x/evm/statedb" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto" ) var ( - _ statedb.Keeper = &MockKeeper{} - errAddress common.Address = common.BigToAddress(big.NewInt(100)) - emptyCodeHash = crypto.Keccak256(nil) + _ statedb.Keeper = &MockKeeper{} + errAddress common.Address = common.BigToAddress(big.NewInt(100)) ) type MockAcount struct { @@ -95,7 +93,7 @@ func (k MockKeeper) DeleteAccount(_ sdk.Context, addr common.Address) error { } old := k.accounts[addr] delete(k.accounts, addr) - if !bytes.Equal(old.account.CodeHash, emptyCodeHash) { + if !evmtypes.IsEmptyCodeHash(common.BytesToHash(old.account.CodeHash)) { delete(k.codes, common.BytesToHash(old.account.CodeHash)) } return nil diff --git a/x/evm/statedb/statedb_test.go b/x/evm/statedb/statedb_test.go index 7027971d72..f9b81520c4 100644 --- a/x/evm/statedb/statedb_test.go +++ b/x/evm/statedb/statedb_test.go @@ -1,6 +1,7 @@ package statedb_test import ( + "github.com/EscanBE/evermint/v12/x/evm/types" "math/big" "testing" @@ -57,7 +58,7 @@ func (suite *StateDBTestSuite) TestAccount() { suite.Require().Equal(true, db.Empty(address)) suite.Require().Equal(big.NewInt(0), db.GetBalance(address)) suite.Require().Equal([]byte(nil), db.GetCode(address)) - suite.Require().Equal(common.BytesToHash(emptyCodeHash), db.GetCodeHash(address)) + suite.Require().True(types.IsEmptyCodeHash(db.GetCodeHash(address))) suite.Require().Equal(uint64(0), db.GetNonce(address)) }}, {"suicide", func(db *statedb.StateDB) { @@ -257,7 +258,7 @@ func (suite *StateDBTestSuite) TestCode() { {"non-exist account", func(vm.StateDB) {}, nil, common.Hash{}}, {"empty account", func(db vm.StateDB) { db.CreateAccount(address) - }, nil, common.BytesToHash(emptyCodeHash)}, + }, nil, common.BytesToHash(types.EmptyCodeHash)}, {"set code", func(db vm.StateDB) { db.SetCode(address, code) }, code, codeHash}, diff --git a/x/evm/types/query.pb.go b/x/evm/types/query.pb.go index 74eb45f02f..b0e646bbd0 100644 --- a/x/evm/types/query.pb.go +++ b/x/evm/types/query.pb.go @@ -1446,8 +1446,7 @@ type QueryClient interface { // ValidatorAccount queries an Ethereum account's from a validator consensus // Address. ValidatorAccount(ctx context.Context, in *QueryValidatorAccountRequest, opts ...grpc.CallOption) (*QueryValidatorAccountResponse, error) - // Balance queries the balance of a the EVM denomination for a single - // EthAccount. + // Balance queries the balance of a the EVM denomination for a single account. Balance(ctx context.Context, in *QueryBalanceRequest, opts ...grpc.CallOption) (*QueryBalanceResponse, error) // Storage queries the balance of all coins for a single account. Storage(ctx context.Context, in *QueryStorageRequest, opts ...grpc.CallOption) (*QueryStorageResponse, error) @@ -1593,8 +1592,7 @@ type QueryServer interface { // ValidatorAccount queries an Ethereum account's from a validator consensus // Address. ValidatorAccount(context.Context, *QueryValidatorAccountRequest) (*QueryValidatorAccountResponse, error) - // Balance queries the balance of a the EVM denomination for a single - // EthAccount. + // Balance queries the balance of a the EVM denomination for a single account. Balance(context.Context, *QueryBalanceRequest) (*QueryBalanceResponse, error) // Storage queries the balance of all coins for a single account. Storage(context.Context, *QueryStorageRequest) (*QueryStorageResponse, error) From 413233526d09da9813c1dac4c71622fa817e7d3f Mon Sep 17 00:00:00 2001 From: VictorTrustyDev Date: Tue, 3 Sep 2024 03:34:44 +0700 Subject: [PATCH 3/6] update swagger --- client/docs/swagger-ui/swagger.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/docs/swagger-ui/swagger.yaml b/client/docs/swagger-ui/swagger.yaml index 4763e938e3..642a4eef76 100644 --- a/client/docs/swagger-ui/swagger.yaml +++ b/client/docs/swagger-ui/swagger.yaml @@ -521,9 +521,9 @@ paths: - Query /evmos/evm/v1/balances/{address}: get: - summary: |- + summary: >- Balance queries the balance of a the EVM denomination for a single - EthAccount. + account. operationId: Balance responses: '200': From 5880f8eab0e62937c9ae684e0b3b1f96ebbe2eee Mon Sep 17 00:00:00 2001 From: VictorTrustyDev Date: Tue, 3 Sep 2024 03:42:07 +0700 Subject: [PATCH 4/6] add IterateContracts --- x/evm/genesis.go | 11 ++++------- x/evm/keeper/statedb.go | 18 ++++++++++++++++++ x/evm/module.go | 2 +- 3 files changed, 23 insertions(+), 8 deletions(-) diff --git a/x/evm/genesis.go b/x/evm/genesis.go index e0444bbad8..79b5c7924d 100644 --- a/x/evm/genesis.go +++ b/x/evm/genesis.go @@ -68,21 +68,18 @@ func InitGenesis( } // ExportGenesis exports genesis state of the EVM module -func ExportGenesis(ctx sdk.Context, k *keeper.Keeper, ak types.AccountKeeper) *types.GenesisState { +func ExportGenesis(ctx sdk.Context, k *keeper.Keeper) *types.GenesisState { var ethGenAccounts []types.GenesisAccount - ak.IterateAccounts(ctx, func(account authtypes.AccountI) bool { - accAddr := account.GetAddress() - codeHash := k.GetCodeHash(ctx, accAddr) + k.IterateContracts(ctx, func(addr common.Address, codeHash common.Hash) bool { if types.IsEmptyCodeHash(codeHash) { // ignore non-contract accounts return false } - ethAddr := common.BytesToAddress(accAddr) - storage := k.GetAccountStorage(ctx, ethAddr) + storage := k.GetAccountStorage(ctx, addr) genAccount := types.GenesisAccount{ - Address: ethAddr.String(), + Address: addr.String(), Code: common.Bytes2Hex(k.GetCode(ctx, codeHash)), Storage: storage, } diff --git a/x/evm/keeper/statedb.go b/x/evm/keeper/statedb.go index fe0a858f8b..9287bb6257 100644 --- a/x/evm/keeper/statedb.go +++ b/x/evm/keeper/statedb.go @@ -252,6 +252,24 @@ func (k *Keeper) DeleteCodeHash(ctx sdk.Context, addr []byte) { store.Delete(addr) } +// IterateContracts iterating through all code hash, represents for all smart contracts +func (k Keeper) IterateContracts(ctx sdk.Context, callback func(addr common.Address, codeHash common.Hash) (stop bool)) { + store := ctx.KVStore(k.storeKey) + iterator := sdk.KVStorePrefixIterator(store, types.KeyPrefixCodeHash) + + defer func() { + _ = iterator.Close() + }() + for ; iterator.Valid(); iterator.Next() { + addr := common.BytesToAddress(iterator.Key()) + codeHash := common.BytesToHash(iterator.Value()) + + if callback(addr, codeHash) { + break + } + } +} + // isNotProhibitedAccountType returns false if the given account is module account or vesting account func isNotProhibitedAccountType(accI authtypes.AccountI) (notProhibited bool, explain string) { if moduleAccount, isModuleAccount := accI.(authtypes.ModuleAccountI); isModuleAccount { diff --git a/x/evm/module.go b/x/evm/module.go index 4421e1b526..422511de19 100644 --- a/x/evm/module.go +++ b/x/evm/module.go @@ -158,7 +158,7 @@ func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, data json. // ExportGenesis returns the exported genesis state as raw bytes for the evm // module. func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) json.RawMessage { - gs := ExportGenesis(ctx, am.keeper, am.ak) + gs := ExportGenesis(ctx, am.keeper) return cdc.MustMarshalJSON(gs) } From fc06b3da011e08aa6ce068d8ce6bc00c2fc4a825 Mon Sep 17 00:00:00 2001 From: VictorTrustyDev Date: Tue, 3 Sep 2024 04:19:10 +0700 Subject: [PATCH 5/6] check spendable balance for EOA --- app/ante/evm/eth.go | 26 +++++++-- app/ante/evm/eth_test.go | 110 ++++++++++++++++++++++++------------ app/ante/handler_options.go | 2 +- x/evm/keeper/statedb.go | 18 +----- x/evm/types/interfaces.go | 1 + 5 files changed, 100 insertions(+), 57 deletions(-) diff --git a/app/ante/evm/eth.go b/app/ante/evm/eth.go index 9a2a03d90d..58e3bee596 100644 --- a/app/ante/evm/eth.go +++ b/app/ante/evm/eth.go @@ -20,18 +20,18 @@ import ( ethtypes "github.com/ethereum/go-ethereum/core/types" ) -// TODO EA: validate if vesting account has enough balance to send - // ExternalOwnedAccountVerificationDecorator validates an account balance checks type ExternalOwnedAccountVerificationDecorator struct { ak evmtypes.AccountKeeper + bk evmtypes.BankKeeper evmKeeper EVMKeeper } // NewExternalOwnedAccountVerificationDecorator creates a new ExternalOwnedAccountVerificationDecorator -func NewExternalOwnedAccountVerificationDecorator(ak evmtypes.AccountKeeper, ek EVMKeeper) ExternalOwnedAccountVerificationDecorator { +func NewExternalOwnedAccountVerificationDecorator(ak evmtypes.AccountKeeper, bk evmtypes.BankKeeper, ek EVMKeeper) ExternalOwnedAccountVerificationDecorator { return ExternalOwnedAccountVerificationDecorator{ ak: ak, + bk: bk, evmKeeper: ek, } } @@ -52,6 +52,8 @@ func (avd ExternalOwnedAccountVerificationDecorator) AnteHandle( return next(ctx, tx, simulate) } + var params *evmtypes.Params + for i, msg := range tx.GetMsgs() { msgEthTx, ok := msg.(*evmtypes.MsgEthereumTx) if !ok { @@ -84,7 +86,23 @@ func (avd ExternalOwnedAccountVerificationDecorator) AnteHandle( ) } - if err := keeper.CheckSenderBalance(sdkmath.NewIntFromBigInt(acct.Balance), txData); err != nil { + var spendableBalance *big.Int + if acct.Balance != nil && acct.Balance.Sign() > 0 { + if params == nil { + p := avd.evmKeeper.GetParams(ctx) + params = &p + } + spendableCoin := avd.bk.SpendableCoin(ctx, from, params.EvmDenom) + if spendableCoin.IsNil() || spendableCoin.IsZero() { + spendableBalance = common.Big0 + } else { + spendableBalance = spendableCoin.Amount.BigInt() + } + } else { + spendableBalance = acct.Balance + } + + if err := keeper.CheckSenderBalance(sdkmath.NewIntFromBigInt(spendableBalance), txData); err != nil { return ctx, errorsmod.Wrap(err, "failed to check sender balance") } } diff --git a/app/ante/evm/eth_test.go b/app/ante/evm/eth_test.go index b6159b2fd1..d602b5d6a5 100644 --- a/app/ante/evm/eth_test.go +++ b/app/ante/evm/eth_test.go @@ -2,8 +2,11 @@ package evm_test import ( "github.com/EscanBE/evermint/v12/constants" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + vestingtypes "github.com/cosmos/cosmos-sdk/x/auth/vesting/types" "math" "math/big" + "time" sdk "github.com/cosmos/cosmos-sdk/types" @@ -20,7 +23,7 @@ import ( func (suite *AnteTestSuite) TestNewExternalOwnedAccountVerificationDecorator() { dec := ethante.NewExternalOwnedAccountVerificationDecorator( - suite.app.AccountKeeper, suite.app.EvmKeeper, + suite.app.AccountKeeper, suite.app.BankKeeper, suite.app.EvmKeeper, ) addr := testutiltx.GenerateAddress() @@ -36,74 +39,109 @@ func (suite *AnteTestSuite) TestNewExternalOwnedAccountVerificationDecorator() { tx := evmtypes.NewTx(ethContractCreationTxParams) tx.From = addr.Hex() - var vmdb *statedb.StateDB - testCases := []struct { name string tx sdk.Tx - malleate func() + malleate func(sdk.Context, *statedb.StateDB) checkTx bool expPass bool }{ - {"not CheckTx", nil, func() {}, false, true}, - {"invalid transaction type", &testutiltx.InvalidTx{}, func() {}, true, false}, { - "sender not set to msg", - tx, - func() {}, - true, - false, + name: "not CheckTx", + tx: nil, + malleate: func(_ sdk.Context, _ *statedb.StateDB) {}, + checkTx: false, + expPass: true, }, { - "sender not EOA", - tx, - func() { + name: "invalid transaction type", + tx: &testutiltx.InvalidTx{}, + malleate: func(_ sdk.Context, _ *statedb.StateDB) {}, + checkTx: true, + expPass: false, + }, + { + name: "sender not set to msg", + tx: tx, + malleate: func(_ sdk.Context, _ *statedb.StateDB) {}, + checkTx: true, + expPass: false, + }, + { + name: "sender not EOA", + tx: tx, + malleate: func(_ sdk.Context, vmdb *statedb.StateDB) { // set not as an EOA vmdb.SetCode(addr, []byte("1")) }, - true, - false, + checkTx: true, + expPass: false, }, { - "not enough balance to cover tx cost", - tx, - func() { + name: "not enough balance to cover tx cost", + tx: tx, + malleate: func(_ sdk.Context, vmdb *statedb.StateDB) { // reset back to EOA vmdb.SetCode(addr, nil) }, - true, - false, + checkTx: true, + expPass: false, }, { - "success new account", - tx, - func() { + name: "success new account", + tx: tx, + malleate: func(_ sdk.Context, vmdb *statedb.StateDB) { vmdb.AddBalance(addr, big.NewInt(1000000)) }, - true, - true, + checkTx: true, + expPass: true, }, { - "success existing account", - tx, - func() { - acc := suite.app.AccountKeeper.NewAccountWithAddress(suite.ctx, addr.Bytes()) - suite.app.AccountKeeper.SetAccount(suite.ctx, acc) + name: "success existing account", + tx: tx, + malleate: func(ctx sdk.Context, vmdb *statedb.StateDB) { + acc := suite.app.AccountKeeper.NewAccountWithAddress(ctx, addr.Bytes()) + suite.app.AccountKeeper.SetAccount(ctx, acc) vmdb.AddBalance(addr, big.NewInt(1000000)) }, - true, - true, + checkTx: true, + expPass: true, + }, + { + name: "not enough spendable balance", + tx: tx, + malleate: func(ctx sdk.Context, vmdb *statedb.StateDB) { + acc := suite.app.AccountKeeper.NewAccountWithAddress(ctx, addr.Bytes()) + + const amount = 1_000_000 + + baseVestingAcc := &vestingtypes.BaseVestingAccount{ + BaseAccount: acc.(*authtypes.BaseAccount), + OriginalVesting: sdk.NewCoins(sdk.NewCoin(constants.BaseDenom, sdk.NewInt(amount))), + DelegatedFree: sdk.NewCoins(sdk.NewCoin(constants.BaseDenom, sdk.NewInt(0))), + DelegatedVesting: sdk.NewCoins(sdk.NewCoin(constants.BaseDenom, sdk.NewInt(0))), + EndTime: ctx.BlockTime().Add(99 * 365 * 24 * time.Hour).Unix(), + } + suite.app.AccountKeeper.SetAccount(ctx, &vestingtypes.DelayedVestingAccount{ + BaseVestingAccount: baseVestingAcc, + }) + + vmdb.AddBalance(addr, big.NewInt(amount)) + }, + checkTx: true, + expPass: false, }, } for _, tc := range testCases { suite.Run(tc.name, func() { - vmdb = testutil.NewStateDB(suite.ctx, suite.app.EvmKeeper) - tc.malleate() + ctx, _ := suite.ctx.CacheContext() + vmdb := testutil.NewStateDB(ctx, suite.app.EvmKeeper) + tc.malleate(ctx, vmdb) suite.Require().NoError(vmdb.Commit()) - _, err := dec.AnteHandle(suite.ctx.WithIsCheckTx(tc.checkTx), tc.tx, false, testutil.NextFn) + _, err := dec.AnteHandle(ctx.WithIsCheckTx(tc.checkTx), tc.tx, false, testutil.NextFn) if tc.expPass { suite.Require().NoError(err) diff --git a/app/ante/handler_options.go b/app/ante/handler_options.go index 642ae516db..57a5e06157 100644 --- a/app/ante/handler_options.go +++ b/app/ante/handler_options.go @@ -104,7 +104,7 @@ func newEVMAnteHandler(options HandlerOptions) sdk.AnteHandler { evmante.NewEthMinGasPriceDecorator(options.FeeMarketKeeper, options.EvmKeeper), evmante.NewEthValidateBasicDecorator(options.EvmKeeper), evmante.NewEthSigVerificationDecorator(options.EvmKeeper), - evmante.NewExternalOwnedAccountVerificationDecorator(options.AccountKeeper, options.EvmKeeper), + evmante.NewExternalOwnedAccountVerificationDecorator(options.AccountKeeper, options.BankKeeper, options.EvmKeeper), evmante.NewEthBasicValidationDecorator(), evmante.NewCanTransferDecorator(options.EvmKeeper), evmante.NewEthGasConsumeDecorator(options.BankKeeper, options.DistributionKeeper, options.EvmKeeper, options.StakingKeeper, options.MaxTxGasWanted), diff --git a/x/evm/keeper/statedb.go b/x/evm/keeper/statedb.go index 9287bb6257..765bce8c1b 100644 --- a/x/evm/keeper/statedb.go +++ b/x/evm/keeper/statedb.go @@ -4,6 +4,7 @@ import ( "fmt" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" vestingtypes "github.com/cosmos/cosmos-sdk/x/auth/vesting/types" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" "math/big" sdkmath "cosmossdk.io/math" @@ -282,22 +283,7 @@ func isNotProhibitedAccountType(accI authtypes.AccountI) (notProhibited bool, ex return } - if _, isVestingAccount := accI.(*vestingtypes.ContinuousVestingAccount); isVestingAccount { - explain = fmt.Sprintf("%s is vesting account", accI.GetAddress().String()) - return - } - - if _, isVestingAccount := accI.(*vestingtypes.DelayedVestingAccount); isVestingAccount { - explain = fmt.Sprintf("%s is vesting account", accI.GetAddress().String()) - return - } - - if _, isVestingAccount := accI.(*vestingtypes.PeriodicVestingAccount); isVestingAccount { - explain = fmt.Sprintf("%s is vesting account", accI.GetAddress().String()) - return - } - - if _, isVestingAccount := accI.(*vestingtypes.PermanentLockedAccount); isVestingAccount { + if _, isVestingAccount := accI.(banktypes.VestingAccount); isVestingAccount { explain = fmt.Sprintf("%s is vesting account", accI.GetAddress().String()) return } diff --git a/x/evm/types/interfaces.go b/x/evm/types/interfaces.go index ed910c7377..4b27e772e0 100644 --- a/x/evm/types/interfaces.go +++ b/x/evm/types/interfaces.go @@ -34,6 +34,7 @@ type BankKeeper interface { SendCoinsFromModuleToAccount(ctx sdk.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins) error MintCoins(ctx sdk.Context, moduleName string, amt sdk.Coins) error BurnCoins(ctx sdk.Context, moduleName string, amt sdk.Coins) error + SpendableCoin(ctx sdk.Context, addr sdk.AccAddress, denom string) sdk.Coin } // StakingKeeper returns the historical headers kept in store. From 9f98af1299f1d07994611bdd769c6301588e4768 Mon Sep 17 00:00:00 2001 From: VictorTrustyDev Date: Tue, 3 Sep 2024 04:21:11 +0700 Subject: [PATCH 6/6] update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 707bcb3924..66ec7f6afb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -102,6 +102,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ - (deps) [#117](https://github.com/EscanBE/evermint/pull/117) Bumps ibc-go to v7.4.0 which include patch for ASA-2024-007 - (deps) [#120](https://github.com/EscanBE/evermint/pull/120) Bump cosmos-sdk v0.47.13, ibc-go v7.8.0, cometbft v0.37.5 - (vesting) [#128](https://github.com/EscanBE/evermint/pull/128) Remove `x/vesting` module and disable vesting +- (evm) [#129](https://github.com/EscanBE/evermint/pull/129) Use generic base account instead of EthAccount # Evermint changelog