From e504a2572f083d91e0a20319f42b1c2866f5fe36 Mon Sep 17 00:00:00 2001 From: codchen Date: Thu, 11 Apr 2024 11:24:53 +0800 Subject: [PATCH 01/17] Add mechanism for benchmarking EVM queries (#1530) * Add mechanism for benchmarking EVM queries * allow ticks to be specified --- integration_test/evm_module/hardhat_test.yaml | 1 + loadtest/config.json | 7 +- loadtest/loadtest_client.go | 1 + loadtest/main.go | 73 ++++++++++++++++++- loadtest/types.go | 7 ++ 5 files changed, 84 insertions(+), 5 deletions(-) diff --git a/integration_test/evm_module/hardhat_test.yaml b/integration_test/evm_module/hardhat_test.yaml index c03595b73..344396b47 100644 --- a/integration_test/evm_module/hardhat_test.yaml +++ b/integration_test/evm_module/hardhat_test.yaml @@ -3,6 +3,7 @@ # Fund owner account in hardhat tests - cmd: printf "12345678\n" | seid tx evm send 0xF87A299e6bC7bEba58dbBe5a5Aa21d49bCD16D52 10000000000000000000 --from admin | cut -d':' -f2- env: TX_HASH + - cmd: sleep 3 - cmd: cast receipt "$TX_HASH" -j |jq -r ."status" env: RESULT # Setup for Hardhat Integration Test diff --git a/loadtest/config.json b/loadtest/config.json index 9b72a6b01..8456cad1b 100644 --- a/loadtest/config.json +++ b/loadtest/config.json @@ -18,6 +18,10 @@ "max": "21", "number_of_distinct_values": 20 }, + "post_tx_evm_queries": { + "block_by_number": 0, + "receipt": 0 + }, "message_configs": { "default": { "gas": 3000000, @@ -115,5 +119,6 @@ "contract_address": "sei1nwp0ynjv84wxysf2f5ctvysl6dpm8ngm70hss6jeqt8q7e7u345s8zru6u", "percentage": "0.1" } - ] + ], + "ticks": 0 } diff --git a/loadtest/loadtest_client.go b/loadtest/loadtest_client.go index 3500bde0e..9c4ee79db 100644 --- a/loadtest/loadtest_client.go +++ b/loadtest/loadtest_client.go @@ -202,6 +202,7 @@ func (c *LoadTestClient) BuildTxs( switch messageType { case EVM, ERC20, ERC721, UNIV2: signedTx = SignedTx{EvmTx: c.generateSignedEvmTx(keyIndex, messageType), MsgType: messageType} + EvmTxHashes = append(EvmTxHashes, signedTx.EvmTx.Hash()) default: msgTypeCount := atomic.LoadInt64(producedCountPerMsgType[messageType]) signedTx = SignedTx{TxBytes: c.generateSignedCosmosTxs(keyIndex, messageType, msgTypeCount), MsgType: messageType} diff --git a/loadtest/main.go b/loadtest/main.go index f4688aba3..1779b5782 100644 --- a/loadtest/main.go +++ b/loadtest/main.go @@ -2,10 +2,12 @@ package main import ( "bytes" + "context" "encoding/json" "flag" "fmt" "io" + "math/big" "math/rand" "net/http" "os" @@ -30,6 +32,7 @@ import ( distributiontypes "github.com/cosmos/cosmos-sdk/x/distribution/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/ethclient" "golang.org/x/sync/semaphore" "golang.org/x/time/rate" @@ -50,6 +53,9 @@ var ( producedCountPerMsgType = make(map[string]*int64) sentCountPerMsgType = make(map[string]*int64) prevSentCounterPerMsgType = make(map[string]*int64) + + BlockHeightsWithTxs = []int{} + EvmTxHashes = []common.Hash{} ) type BlockData struct { @@ -148,6 +154,7 @@ func run(config *Config) { deployEvmContracts(config) deployUniswapContracts(client, config) startLoadtestWorkers(client, *config) + runEvmQueries(*config) } // starts loadtest workers. If config.Constant is true, then we don't gather loadtest results and let producer/consumer @@ -183,6 +190,7 @@ func startLoadtestWorkers(client *LoadTestClient, config Config) { // Statistics reporting goroutine ticker := time.NewTicker(10 * time.Second) + ticks := 0 go func() { start := time.Now() for { @@ -190,13 +198,16 @@ func startLoadtestWorkers(client *LoadTestClient, config Config) { case <-ticker.C: currHeight := getLastHeight(config.BlockchainEndpoint) for i := startHeight; i <= currHeight; i++ { - _, blockTime, err := getTxBlockInfo(config.BlockchainEndpoint, strconv.Itoa(i)) + txCnt, blockTime, err := getTxBlockInfo(config.BlockchainEndpoint, strconv.Itoa(i)) if err != nil { fmt.Printf("Encountered error scraping data: %s\n", err) return } blockHeights = append(blockHeights, i) blockTimes = append(blockTimes, blockTime) + if txCnt > 0 { + BlockHeightsWithTxs = append(BlockHeightsWithTxs, i) + } } printStats(start, producedCountPerMsgType, sentCountPerMsgType, prevSentCounterPerMsgType, blockHeights, blockTimes) @@ -208,6 +219,10 @@ func startLoadtestWorkers(client *LoadTestClient, config Config) { count := atomic.LoadInt64(sentCountPerMsgType[msgType]) atomic.StoreInt64(prevSentCounterPerMsgType[msgType], count) } + ticks++ + if config.Ticks > 0 && ticks >= int(config.Ticks) { + close(done) + } case <-done: ticker.Stop() return @@ -216,9 +231,11 @@ func startLoadtestWorkers(client *LoadTestClient, config Config) { }() // Wait for a termination signal - <-signals - fmt.Println("SIGINT received, shutting down producers and consumers...") - close(done) + if config.Ticks == 0 { + <-signals + fmt.Println("SIGINT received, shutting down producers and consumers...") + close(done) + } fmt.Println("Waiting for wait groups...") @@ -756,6 +773,54 @@ func getTxBlockInfo(blockchainEndpoint string, height string) (int, string, erro return len(blockResponse.Block.Data.Txs), blockResponse.Block.Header.Time, nil } +func runEvmQueries(config Config) { + ethEndpoints := strings.Split(config.EvmRpcEndpoints, ",") + if len(ethEndpoints) == 0 { + return + } + ethClients := make([]*ethclient.Client, len(ethEndpoints)) + for i, endpoint := range ethEndpoints { + client, err := ethclient.Dial(endpoint) + if err != nil { + fmt.Printf("Failed to connect to endpoint %s with error %s", endpoint, err.Error()) + } + ethClients[i] = client + } + wg := sync.WaitGroup{} + start := time.Now() + for i := 0; i < config.PostTxEvmQueries.BlockByNumber; i++ { + wg.Add(1) + i := i + go func() { + defer func() { wg.Done() }() + height := int64(BlockHeightsWithTxs[i%len(BlockHeightsWithTxs)]) + _, err := ethClients[i%len(ethClients)].BlockByNumber(context.Background(), big.NewInt(height)) + if err != nil { + fmt.Printf("Failed to get full block of height %d due to %s\n", height, err) + } + }() + } + wg.Wait() + fmt.Printf("Querying %d blocks in parallel took %fs\n", config.PostTxEvmQueries.BlockByNumber, time.Since(start).Seconds()) + + wg = sync.WaitGroup{} + start = time.Now() + for i := 0; i < config.PostTxEvmQueries.Receipt; i++ { + wg.Add(1) + i := i + go func() { + defer func() { wg.Done() }() + hash := EvmTxHashes[i%len(EvmTxHashes)] + _, err := ethClients[i%len(ethClients)].TransactionReceipt(context.Background(), hash) + if err != nil { + fmt.Printf("Failed to get receipt of tx %s due to %s\n", hash.Hex(), err) + } + }() + } + wg.Wait() + fmt.Printf("Querying %d receipts in parallel took %fs\n", config.PostTxEvmQueries.Receipt, time.Since(start).Seconds()) +} + func GetDefaultConfigFilePath() string { pwd, _ := os.Getwd() return pwd + "/loadtest/config.json" diff --git a/loadtest/types.go b/loadtest/types.go index 422f277eb..573cb839d 100644 --- a/loadtest/types.go +++ b/loadtest/types.go @@ -69,6 +69,8 @@ type Config struct { MetricsPort uint64 `json:"metrics_port"` TLS bool `json:"tls"` SeiTesterAddress string `json:"sei_tester_address"` + PostTxEvmQueries PostTxEvmQueries `json:"post_tx_evm_queries"` + Ticks uint64 `json:"ticks"` // These are dynamically set at startup EVMAddresses *EVMAddresses @@ -211,6 +213,11 @@ type WasmInstantiateType struct { Payload string `json:"payload"` } +type PostTxEvmQueries struct { + BlockByNumber int `json:"block_by_number"` + Receipt int `json:"receipt"` +} + type SignedTx struct { TxBytes []byte EvmTx *ethtypes.Transaction From 37251b2143442774d8a97abb7597c8c7239665d2 Mon Sep 17 00:00:00 2001 From: codchen Date: Thu, 11 Apr 2024 11:25:32 +0800 Subject: [PATCH 02/17] Use random string filter ID instead of incrementing ints (#1527) --- evmrpc/filter.go | 27 ++++++++++++--------------- evmrpc/filter_test.go | 22 +++++++++++----------- 2 files changed, 23 insertions(+), 26 deletions(-) diff --git a/evmrpc/filter.go b/evmrpc/filter.go index 0900b4fea..41d246b98 100644 --- a/evmrpc/filter.go +++ b/evmrpc/filter.go @@ -12,6 +12,7 @@ import ( "github.com/ethereum/go-ethereum/common" ethtypes "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/eth/filters" + ethrpc "github.com/ethereum/go-ethereum/rpc" "github.com/sei-protocol/sei-chain/utils" "github.com/sei-protocol/sei-chain/x/evm/keeper" rpcclient "github.com/tendermint/tendermint/rpc/client" @@ -43,9 +44,8 @@ type filter struct { type FilterAPI struct { tmClient rpcclient.Client - nextFilterID uint64 filtersMu sync.Mutex - filters map[uint64]filter + filters map[ethrpc.ID]filter filterConfig *FilterConfig logFetcher *LogFetcher } @@ -60,10 +60,9 @@ type EventItemDataWrapper struct { } func NewFilterAPI(tmClient rpcclient.Client, logFetcher *LogFetcher, filterConfig *FilterConfig) *FilterAPI { - filters := make(map[uint64]filter) + filters := make(map[ethrpc.ID]filter) api := &FilterAPI{ tmClient: tmClient, - nextFilterID: 1, filtersMu: sync.Mutex{}, filters: filters, filterConfig: filterConfig, @@ -96,38 +95,36 @@ func (a *FilterAPI) timeoutLoop(timeout time.Duration) { func (a *FilterAPI) NewFilter( _ context.Context, crit filters.FilterCriteria, -) (*uint64, error) { +) (ethrpc.ID, error) { a.filtersMu.Lock() defer a.filtersMu.Unlock() - curFilterID := a.nextFilterID - a.nextFilterID++ + curFilterID := ethrpc.NewID() a.filters[curFilterID] = filter{ typ: LogsSubscription, fc: crit, deadline: time.NewTimer(a.filterConfig.timeout), lastToHeight: 0, } - return &curFilterID, nil + return curFilterID, nil } func (a *FilterAPI) NewBlockFilter( _ context.Context, -) (*uint64, error) { +) (ethrpc.ID, error) { a.filtersMu.Lock() defer a.filtersMu.Unlock() - curFilterID := a.nextFilterID - a.nextFilterID++ + curFilterID := ethrpc.NewID() a.filters[curFilterID] = filter{ typ: BlocksSubscription, deadline: time.NewTimer(a.filterConfig.timeout), blockCursor: "", } - return &curFilterID, nil + return curFilterID, nil } func (a *FilterAPI) GetFilterChanges( ctx context.Context, - filterID uint64, + filterID ethrpc.ID, ) (interface{}, error) { a.filtersMu.Lock() defer a.filtersMu.Unlock() @@ -177,7 +174,7 @@ func (a *FilterAPI) GetFilterChanges( func (a *FilterAPI) GetFilterLogs( ctx context.Context, - filterID uint64, + filterID ethrpc.ID, ) ([]*ethtypes.Log, error) { a.filtersMu.Lock() defer a.filtersMu.Unlock() @@ -251,7 +248,7 @@ func (a *FilterAPI) getBlockHeadersAfter( func (a *FilterAPI) UninstallFilter( _ context.Context, - filterID uint64, + filterID ethrpc.ID, ) bool { a.filtersMu.Lock() defer a.filtersMu.Unlock() diff --git a/evmrpc/filter_test.go b/evmrpc/filter_test.go index 650a55d7c..9480400b4 100644 --- a/evmrpc/filter_test.go +++ b/evmrpc/filter_test.go @@ -61,10 +61,10 @@ func TestFilterNew(t *testing.T) { require.True(t, errExists) } else { require.False(t, errExists, "error should not exist") - got := resObj["result"].(float64) + got := resObj["result"].(string) // make sure next filter id is not equal to this one resObj := sendRequestGood(t, "newFilter", filterCriteria) - got2 := resObj["result"].(float64) + got2 := resObj["result"].(string) require.NotEqual(t, got, got2) } }) @@ -79,15 +79,15 @@ func TestFilterUninstall(t *testing.T) { "toBlock": "0xa", } resObj := sendRequestGood(t, "newFilter", filterCriteria) - filterId := int(resObj["result"].(float64)) - require.GreaterOrEqual(t, filterId, 1) + filterId := resObj["result"].(string) + require.NotEmpty(t, filterId) resObj = sendRequest(t, TestPort, "uninstallFilter", filterId) uninstallSuccess := resObj["result"].(bool) require.True(t, uninstallSuccess) // uninstall non-existing filter - nonExistingFilterId := 100 + nonExistingFilterId := "100" resObj = sendRequest(t, TestPort, "uninstallFilter", nonExistingFilterId) uninstallSuccess = resObj["result"].(bool) require.False(t, uninstallSuccess) @@ -220,7 +220,7 @@ func TestFilterGetFilterLogs(t *testing.T) { "toBlock": "0x2", } resObj := sendRequestGood(t, "newFilter", filterCriteria) - filterId := int(resObj["result"].(float64)) + filterId := resObj["result"].(string) resObj = sendRequest(t, TestPort, "getFilterLogs", filterId) logs := resObj["result"].([]interface{}) @@ -242,7 +242,7 @@ func TestFilterGetFilterChanges(t *testing.T) { "fromBlock": "0x2", } resObj := sendRequest(t, TestPort, "newFilter", filterCriteria) - filterId := int(resObj["result"].(float64)) + filterId := resObj["result"].(string) resObj = sendRequest(t, TestPort, "getFilterChanges", filterId) logs := resObj["result"].([]interface{}) @@ -284,7 +284,7 @@ func TestFilterGetFilterChanges(t *testing.T) { func TestFilterBlockFilter(t *testing.T) { t.Parallel() resObj := sendRequestGood(t, "newBlockFilter") - blockFilterId := int(resObj["result"].(float64)) + blockFilterId := resObj["result"].(string) resObj = sendRequestGood(t, "getFilterChanges", blockFilterId) hashesInterface := resObj["result"].([]interface{}) for _, hashInterface := range hashesInterface { @@ -309,7 +309,7 @@ func TestFilterExpiration(t *testing.T) { "toBlock": "0xa", } resObj := sendRequestGood(t, "newFilter", filterCriteria) - filterId := int(resObj["result"].(float64)) + filterId := resObj["result"].(string) // wait for filter to expire time.Sleep(2 * filterTimeoutDuration) @@ -326,7 +326,7 @@ func TestFilterGetFilterLogsKeepsFilterAlive(t *testing.T) { "toBlock": "0xa", } resObj := sendRequestGood(t, "newFilter", filterCriteria) - filterId := int(resObj["result"].(float64)) + filterId := resObj["result"].(string) for i := 0; i < 5; i++ { // should keep filter alive @@ -344,7 +344,7 @@ func TestFilterGetFilterChangesKeepsFilterAlive(t *testing.T) { "toBlock": "0xa", } resObj := sendRequestGood(t, "newFilter", filterCriteria) - filterId := int(resObj["result"].(float64)) + filterId := resObj["result"].(string) for i := 0; i < 5; i++ { // should keep filter alive From 94af30212cc7c876ba5072785cfc2c6eee8dd59e Mon Sep 17 00:00:00 2001 From: Yiming Zang <50607998+yzang2019@users.noreply.github.com> Date: Thu, 11 Apr 2024 15:05:10 +0800 Subject: [PATCH 03/17] Add unit test for x/evm/state (#1532) --- x/evm/state/nonce_test.go | 21 +++++++++++++++++++++ x/evm/state/utils.go | 2 +- x/evm/state/utils_test.go | 5 +++++ 3 files changed, 27 insertions(+), 1 deletion(-) create mode 100644 x/evm/state/nonce_test.go diff --git a/x/evm/state/nonce_test.go b/x/evm/state/nonce_test.go new file mode 100644 index 000000000..ed8b579f0 --- /dev/null +++ b/x/evm/state/nonce_test.go @@ -0,0 +1,21 @@ +package state_test + +import ( + "github.com/stretchr/testify/require" + "testing" + + testkeeper "github.com/sei-protocol/sei-chain/testutil/keeper" + "github.com/sei-protocol/sei-chain/x/evm/state" +) + +func TestNonce(t *testing.T) { + k, ctx := testkeeper.MockEVMKeeper() + stateDB := state.NewDBImpl(ctx, k, false) + _, addr := testkeeper.MockAddressPair() + stateDB.SetNonce(addr, 1) + nonce := stateDB.GetNonce(addr) + require.Equal(t, nonce, uint64(1)) + stateDB.SetNonce(addr, 2) + nonce = stateDB.GetNonce(addr) + require.Equal(t, nonce, uint64(2)) +} diff --git a/x/evm/state/utils.go b/x/evm/state/utils.go index 42b7cb229..5ad268b39 100644 --- a/x/evm/state/utils.go +++ b/x/evm/state/utils.go @@ -17,7 +17,7 @@ var CoinbaseAddressPrefix = []byte("evm_coinbase") func GetCoinbaseAddress(txIdx int) sdk.AccAddress { txIndexBz := make([]byte, 8) binary.BigEndian.PutUint64(txIndexBz, uint64(txIdx)) - return sdk.AccAddress(append(CoinbaseAddressPrefix, txIndexBz...)) + return append(CoinbaseAddressPrefix, txIndexBz...) } func SplitUseiWeiAmount(amt *big.Int) (sdk.Int, sdk.Int) { diff --git a/x/evm/state/utils_test.go b/x/evm/state/utils_test.go index 0fe6ea334..37b1c2414 100644 --- a/x/evm/state/utils_test.go +++ b/x/evm/state/utils_test.go @@ -8,6 +8,11 @@ import ( "github.com/stretchr/testify/require" ) +func TestGetCoinbaseAddress(t *testing.T) { + coinbaseAddr := state.GetCoinbaseAddress(1) + require.Equal(t, coinbaseAddr, "sei1v4mx6hmrda5kucnpwdjsqqqqqqqqqqqpz6djs7") +} + func TestSplitUseiWeiAmount(t *testing.T) { for _, test := range []struct { amt *big.Int From cec5ad5879f6c0d699bf5944a503cfffa6ff37a4 Mon Sep 17 00:00:00 2001 From: codchen Date: Thu, 11 Apr 2024 21:22:32 +0800 Subject: [PATCH 04/17] Check wei balance in associate tx handling (#1534) --- x/evm/ante/preprocess.go | 19 ++++++++++++++---- x/evm/ante/preprocess_test.go | 38 +++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 4 deletions(-) diff --git a/x/evm/ante/preprocess.go b/x/evm/ante/preprocess.go index 0d5ad21de..30bbd9c1e 100644 --- a/x/evm/ante/preprocess.go +++ b/x/evm/ante/preprocess.go @@ -15,6 +15,7 @@ import ( accountkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper" authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" "github.com/ethereum/go-ethereum/common" ethtypes "github.com/ethereum/go-ethereum/core/types" @@ -31,6 +32,9 @@ import ( // Accounts need to have at least 1Sei to force association. Note that account won't be charged. const BalanceThreshold uint64 = 1000000 +var BigBalanceThreshold *big.Int = new(big.Int).SetUint64(BalanceThreshold) +var BigBalanceThresholdMinus1 *big.Int = new(big.Int).SetUint64(BalanceThreshold - 1) + var SignerMap = map[derived.SignerVersion]func(*big.Int) ethtypes.Signer{ derived.London: ethtypes.NewLondonSigner, derived.Cancun: ethtypes.NewCancunSigner, @@ -71,11 +75,18 @@ func (p *EVMPreprocessDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate // check if the account has enough balance (without charging) baseDenom := p.evmKeeper.GetBaseDenom(ctx) seiBalance := p.evmKeeper.BankKeeper().GetBalance(ctx, seiAddr, baseDenom).Amount - // no need to get wei balance here since the sei address is not used directly in EVM and thus does not - // contain any wei, so any wei balance in `sdk.AccAddress(evmAddr[:])` would not add up to 1usei anyway. castBalance := p.evmKeeper.BankKeeper().GetBalance(ctx, sdk.AccAddress(evmAddr[:]), baseDenom).Amount - if new(big.Int).Add(seiBalance.BigInt(), castBalance.BigInt()).Cmp(new(big.Int).SetUint64(BalanceThreshold)) < 0 { - return ctx, sdkerrors.Wrap(sdkerrors.ErrInsufficientFunds, "account needs to have at least 1Sei to force association") + totalUsei := new(big.Int).Add(seiBalance.BigInt(), castBalance.BigInt()) + if totalUsei.Cmp(BigBalanceThreshold) < 0 { + if totalUsei.Cmp(BigBalanceThresholdMinus1) < 0 { + // no need to check for wei balances since the sum wouldn't reach 2usei + return ctx, sdkerrors.Wrap(sdkerrors.ErrInsufficientFunds, "account needs to have at least 1Sei to force association") + } + seiWeiBalance := p.evmKeeper.BankKeeper().GetWeiBalance(ctx, seiAddr) + evmWeiBalance := p.evmKeeper.BankKeeper().GetWeiBalance(ctx, sdk.AccAddress(evmAddr[:])) + if seiWeiBalance.Add(evmWeiBalance).LT(bankkeeper.OneUseiInWei) { + return ctx, sdkerrors.Wrap(sdkerrors.ErrInsufficientFunds, "account needs to have at least 1Sei to force association") + } } if err := p.associateAddresses(ctx, seiAddr, evmAddr, pubkey); err != nil { return ctx, err diff --git a/x/evm/ante/preprocess_test.go b/x/evm/ante/preprocess_test.go index 2756f9184..cdc39ce95 100644 --- a/x/evm/ante/preprocess_test.go +++ b/x/evm/ante/preprocess_test.go @@ -11,6 +11,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" sdkacltypes "github.com/cosmos/cosmos-sdk/types/accesscontrol" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" "github.com/ethereum/go-ethereum/common" ethtypes "github.com/ethereum/go-ethereum/core/types" @@ -136,6 +137,43 @@ func TestPreprocessAssociateTx(t *testing.T) { require.NotNil(t, err) } +func TestPreprocessAssociateTxWithWeiBalance(t *testing.T) { + k, ctx := testkeeper.MockEVMKeeper() + handler := ante.NewEVMPreprocessDecorator(k, k.AccountKeeper()) + privKey := testkeeper.MockPrivateKey() + testPrivHex := hex.EncodeToString(privKey.Bytes()) + key, _ := crypto.HexToECDSA(testPrivHex) + + emptyData := make([]byte, 32) + prefixedMessage := fmt.Sprintf("\x19Ethereum Signed Message:\n%d", len(emptyData)) + string(emptyData) + hash := crypto.Keccak256Hash([]byte(prefixedMessage)) + sig, err := crypto.Sign(hash.Bytes(), key) + require.Nil(t, err) + R, S, _, _ := ethtx.DecodeSignature(sig) + V := big.NewInt(int64(sig[64])) + + txData := ethtx.AssociateTx{V: V.Bytes(), R: R.Bytes(), S: S.Bytes(), CustomMessage: prefixedMessage} + msg, err := types.NewMsgEVMTransaction(&txData) + require.Nil(t, err) + seiAddr := sdk.AccAddress(privKey.PubKey().Address()) + evmAddr := crypto.PubkeyToAddress(key.PublicKey) + k.BankKeeper().AddCoins(ctx, seiAddr, sdk.NewCoins(sdk.NewCoin(k.GetBaseDenom(ctx), sdk.NewInt(int64(ante.BalanceThreshold-1)))), true) + k.BankKeeper().AddWei(ctx, sdk.AccAddress(evmAddr[:]), bankkeeper.OneUseiInWei.Sub(sdk.OneInt())) + ctx, err = handler.AnteHandle(ctx, mockTx{msgs: []sdk.Msg{msg}}, false, func(ctx sdk.Context, _ sdk.Tx, _ bool) (sdk.Context, error) { + panic("should not be called") + }) + // not enough balance (0.9999999999999999 wei only) + require.NotNil(t, err) + k.BankKeeper().AddWei(ctx, seiAddr, sdk.OneInt()) + ctx, err = handler.AnteHandle(ctx, mockTx{msgs: []sdk.Msg{msg}}, false, func(ctx sdk.Context, _ sdk.Tx, _ bool) (sdk.Context, error) { + panic("should not be called") + }) + require.Nil(t, err) + associated, ok := k.GetEVMAddress(ctx, seiAddr) + require.True(t, ok) + require.Equal(t, evmAddr, associated) +} + func TestGetVersion(t *testing.T) { ethCfg := ¶ms.ChainConfig{} ctx := sdk.Context{}.WithBlockHeight(10).WithBlockTime(time.Now()) From e2514a8e6a0e3942ff059bde5854b536707c767f Mon Sep 17 00:00:00 2001 From: codchen Date: Thu, 11 Apr 2024 21:22:41 +0800 Subject: [PATCH 05/17] Fix balance behavior for selfdestructed accounts (#1526) Emit event for contract registration (#1518) --- x/evm/state/balance.go | 11 +-------- x/evm/state/state.go | 20 ++++++++++++++++- x/evm/state/state_test.go | 6 +++++ x/evm/state/statedb.go | 47 +++++++++++++++++++++++---------------- 4 files changed, 54 insertions(+), 30 deletions(-) diff --git a/x/evm/state/balance.go b/x/evm/state/balance.go index 376826586..493c8e495 100644 --- a/x/evm/state/balance.go +++ b/x/evm/state/balance.go @@ -18,10 +18,6 @@ func (s *DBImpl) SubBalance(evmAddr common.Address, amt *big.Int, reason tracing s.AddBalance(evmAddr, new(big.Int).Neg(amt), reason) return } - if s.HasSelfDestructed(evmAddr) { - // redirect coins to fee collector, since simply burning here would cause coin supply mismatch - evmAddr, _ = s.k.GetFeeCollectorAddress(s.ctx) - } ctx := s.ctx @@ -62,11 +58,6 @@ func (s *DBImpl) AddBalance(evmAddr common.Address, amt *big.Int, reason tracing return } - if s.HasSelfDestructed(evmAddr) { - // redirect coins to fee collector, since simply burning here would cause coin supply mismatch - evmAddr, _ = s.k.GetFeeCollectorAddress(s.ctx) - } - ctx := s.ctx // this avoids emitting cosmos events for ephemeral bookkeeping transfers like send_native if s.eventsSuppressed { @@ -125,7 +116,7 @@ func (s *DBImpl) SetBalance(evmAddr common.Address, amt *big.Int, reason tracing } func (s *DBImpl) getSeiAddress(evmAddr common.Address) sdk.AccAddress { - if feeCollector, _ := s.k.GetFeeCollectorAddress(s.ctx); feeCollector == evmAddr { + if s.coinbaseEvmAddress.Cmp(evmAddr) == 0 { return s.coinbaseAddress } return s.k.GetSeiAddressOrDefault(s.ctx, evmAddr) diff --git a/x/evm/state/state.go b/x/evm/state/state.go index 7405c5818..7d8855176 100644 --- a/x/evm/state/state.go +++ b/x/evm/state/state.go @@ -7,6 +7,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/tracing" + "github.com/sei-protocol/sei-chain/utils" "github.com/sei-protocol/sei-chain/x/evm/types" ) @@ -108,10 +109,27 @@ func (s *DBImpl) RevertToSnapshot(rev int) { s.Snapshot() } +func (s *DBImpl) handleResidualFundsInDestructedAccounts(st *TemporaryState) { + for a, status := range st.transientAccounts { + if !bytes.Equal(status, AccountDeleted) { + continue + } + acc := common.HexToAddress(a) + residual := s.GetBalance(acc) + if residual.Cmp(utils.Big0) == 0 { + continue + } + s.SubBalance(acc, residual, tracing.BalanceDecreaseSelfdestructBurn) + // we don't want to really "burn" the token since it will mess up + // total supply calculation, so we send them to fee collector instead + s.AddBalance(s.coinbaseEvmAddress, residual, tracing.BalanceDecreaseSelfdestructBurn) + } +} + func (s *DBImpl) clearAccountStateIfDestructed(st *TemporaryState) { for acc, status := range st.transientAccounts { if !bytes.Equal(status, AccountDeleted) { - return + continue } s.clearAccountState(common.HexToAddress(acc)) } diff --git a/x/evm/state/state_test.go b/x/evm/state/state_test.go index fe4cc57ff..1b165d63f 100644 --- a/x/evm/state/state_test.go +++ b/x/evm/state/state_test.go @@ -116,11 +116,17 @@ func TestSelfDestructAssociated(t *testing.T) { require.Equal(t, big.NewInt(0), k.BankKeeper().GetBalance(ctx, seiAddr, k.GetBaseDenom(ctx)).Amount.BigInt()) require.True(t, statedb.HasSelfDestructed(evmAddr)) require.False(t, statedb.Created(evmAddr)) + statedb.AddBalance(evmAddr, big.NewInt(1), tracing.BalanceChangeUnspecified) + require.Equal(t, big.NewInt(1), statedb.GetBalance(evmAddr)) statedb.Finalize() require.Equal(t, common.Hash{}, statedb.GetState(evmAddr, key)) // association should also be removed _, ok := k.GetSeiAddress(statedb.Ctx(), evmAddr) require.False(t, ok) + // balance in destructed account should be cleared and transferred to coinbase + require.Equal(t, big.NewInt(0), statedb.GetBalance(evmAddr)) + fc, _ := k.GetFeeCollectorAddress(statedb.Ctx()) + require.Equal(t, big.NewInt(1), statedb.GetBalance(fc)) } func TestSnapshot(t *testing.T) { diff --git a/x/evm/state/statedb.go b/x/evm/state/statedb.go index 6686adb5f..4988b3e9b 100644 --- a/x/evm/state/statedb.go +++ b/x/evm/state/statedb.go @@ -26,7 +26,8 @@ type DBImpl struct { // a temporary address that collects fees for this particular transaction so that there is // no single bottleneck for fee collection. Its account state and balance will be deleted // before the block commits - coinbaseAddress sdk.AccAddress + coinbaseAddress sdk.AccAddress + coinbaseEvmAddress common.Address k EVMKeeper simulation bool @@ -38,13 +39,15 @@ type DBImpl struct { } func NewDBImpl(ctx sdk.Context, k EVMKeeper, simulation bool) *DBImpl { + feeCollector, _ := k.GetFeeCollectorAddress(ctx) s := &DBImpl{ - ctx: ctx, - k: k, - snapshottedCtxs: []sdk.Context{}, - coinbaseAddress: GetCoinbaseAddress(ctx.TxIndex()), - simulation: simulation, - tempStateCurrent: NewTemporaryState(), + ctx: ctx, + k: k, + snapshottedCtxs: []sdk.Context{}, + coinbaseAddress: GetCoinbaseAddress(ctx.TxIndex()), + simulation: simulation, + tempStateCurrent: NewTemporaryState(), + coinbaseEvmAddress: feeCollector, } s.Snapshot() // take an initial snapshot for GetCommitted return s @@ -82,6 +85,14 @@ func (s *DBImpl) Finalize() (surplus sdk.Int, err error) { return } + // delete state of self-destructed accounts + s.handleResidualFundsInDestructedAccounts(s.tempStateCurrent) + s.clearAccountStateIfDestructed(s.tempStateCurrent) + for _, ts := range s.tempStatesHist { + s.handleResidualFundsInDestructedAccounts(ts) + s.clearAccountStateIfDestructed(ts) + } + // remove transient states // write cache to underlying s.flushCtx(s.ctx) @@ -90,12 +101,9 @@ func (s *DBImpl) Finalize() (surplus sdk.Int, err error) { s.flushCtx(s.snapshottedCtxs[i]) } - // delete state of self-destructed accoutns - s.clearAccountStateIfDestructed(s.tempStateCurrent) surplus = s.tempStateCurrent.surplus for _, ts := range s.tempStatesHist { surplus = surplus.Add(ts.surplus) - s.clearAccountStateIfDestructed(ts) } if surplus.IsNegative() { err = fmt.Errorf("negative surplus value: %s", surplus.String()) @@ -119,15 +127,16 @@ func (s *DBImpl) GetStorageRoot(common.Address) common.Hash { func (s *DBImpl) Copy() vm.StateDB { newCtx := s.ctx.WithMultiStore(s.ctx.MultiStore().CacheMultiStore()) return &DBImpl{ - ctx: newCtx, - snapshottedCtxs: append(s.snapshottedCtxs, s.ctx), - tempStateCurrent: NewTemporaryState(), - tempStatesHist: append(s.tempStatesHist, s.tempStateCurrent), - k: s.k, - coinbaseAddress: s.coinbaseAddress, - simulation: s.simulation, - err: s.err, - logger: s.logger, + ctx: newCtx, + snapshottedCtxs: append(s.snapshottedCtxs, s.ctx), + tempStateCurrent: NewTemporaryState(), + tempStatesHist: append(s.tempStatesHist, s.tempStateCurrent), + k: s.k, + coinbaseAddress: s.coinbaseAddress, + coinbaseEvmAddress: s.coinbaseEvmAddress, + simulation: s.simulation, + err: s.err, + logger: s.logger, } } From 95e381ff4cdc4006cbeeb088b63c9d9f3ed62d42 Mon Sep 17 00:00:00 2001 From: Uday Patil Date: Thu, 11 Apr 2024 10:12:00 -0500 Subject: [PATCH 06/17] Bank precompile get balances (#1533) Add bank precompile get all balances for account query --- precompiles/bank/Bank.sol | 11 ++++- precompiles/bank/abi.json | 2 +- precompiles/bank/bank.go | 68 ++++++++++++++++++++------ precompiles/bank/bank_test.go | 31 +++++++++++- precompiles/common/expected_keepers.go | 1 + 5 files changed, 96 insertions(+), 17 deletions(-) mode change 100755 => 100644 precompiles/bank/abi.json diff --git a/precompiles/bank/Bank.sol b/precompiles/bank/Bank.sol index 7d8a0fea1..e57a083ef 100644 --- a/precompiles/bank/Bank.sol +++ b/precompiles/bank/Bank.sol @@ -17,7 +17,7 @@ interface IBank { ) external returns (bool success); function sendNative( - string memory toNativeAddress, + string memory toNativeAddress ) payable external returns (bool success); // Queries @@ -26,6 +26,15 @@ interface IBank { string memory denom ) external view returns (uint256 amount); + struct Coin { + uint256 amount; + string denom; + } + + function all_balances( + address acc + ) external view returns (Coin[] memory response); + function name( string memory denom ) external view returns (string memory response); diff --git a/precompiles/bank/abi.json b/precompiles/bank/abi.json old mode 100755 new mode 100644 index c02ea9c21..844ac4894 --- a/precompiles/bank/abi.json +++ b/precompiles/bank/abi.json @@ -1 +1 @@ -[{"inputs":[{"internalType":"address","name":"acc","type":"address"},{"internalType":"string","name":"denom","type":"string"}],"name":"balance","outputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"denom","type":"string"}],"name":"decimals","outputs":[{"internalType":"uint8","name":"response","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"denom","type":"string"}],"name":"name","outputs":[{"internalType":"string","name":"response","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"fromAddress","type":"address"},{"internalType":"address","name":"toAddress","type":"address"},{"internalType":"string","name":"denom","type":"string"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"send","outputs":[{"internalType":"bool","name":"success","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"denom","type":"string"}],"name":"supply","outputs":[{"internalType":"uint256","name":"response","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"denom","type":"string"}],"name":"symbol","outputs":[{"internalType":"string","name":"response","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"toNativeAddress","type":"string"}],"name":"sendNative","outputs":[{"internalType":"bool","name":"success","type":"bool"}],"stateMutability":"payable","type":"function"}] \ No newline at end of file +[{"inputs":[{"internalType":"address","name":"acc","type":"address"}],"name":"all_balances","outputs":[{"components":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"string","name":"denom","type":"string"}],"internalType":"struct IBank.Coin[]","name":"response","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"acc","type":"address"},{"internalType":"string","name":"denom","type":"string"}],"name":"balance","outputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"denom","type":"string"}],"name":"decimals","outputs":[{"internalType":"uint8","name":"response","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"denom","type":"string"}],"name":"name","outputs":[{"internalType":"string","name":"response","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"fromAddress","type":"address"},{"internalType":"address","name":"toAddress","type":"address"},{"internalType":"string","name":"denom","type":"string"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"send","outputs":[{"internalType":"bool","name":"success","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"toNativeAddress","type":"string"}],"name":"sendNative","outputs":[{"internalType":"bool","name":"success","type":"bool"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"string","name":"denom","type":"string"}],"name":"supply","outputs":[{"internalType":"uint256","name":"response","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"denom","type":"string"}],"name":"symbol","outputs":[{"internalType":"string","name":"response","type":"string"}],"stateMutability":"view","type":"function"}] \ No newline at end of file diff --git a/precompiles/bank/bank.go b/precompiles/bank/bank.go index e030eed3b..395cbd6e1 100644 --- a/precompiles/bank/bank.go +++ b/precompiles/bank/bank.go @@ -17,13 +17,14 @@ import ( ) const ( - SendMethod = "send" - SendNativeMethod = "sendNative" - BalanceMethod = "balance" - NameMethod = "name" - SymbolMethod = "symbol" - DecimalsMethod = "decimals" - SupplyMethod = "supply" + SendMethod = "send" + SendNativeMethod = "sendNative" + BalanceMethod = "balance" + AllBalancesMethod = "all_balances" + NameMethod = "name" + SymbolMethod = "symbol" + DecimalsMethod = "decimals" + SupplyMethod = "supply" ) const ( @@ -56,13 +57,19 @@ type Precompile struct { evmKeeper pcommon.EVMKeeper address common.Address - SendID []byte - SendNativeID []byte - BalanceID []byte - NameID []byte - SymbolID []byte - DecimalsID []byte - SupplyID []byte + SendID []byte + SendNativeID []byte + BalanceID []byte + AllBalancesID []byte + NameID []byte + SymbolID []byte + DecimalsID []byte + SupplyID []byte +} + +type CoinBalance struct { + Amount *big.Int + Denom string } func NewPrecompile(bankKeeper pcommon.BankKeeper, evmKeeper pcommon.EVMKeeper) (*Precompile, error) { @@ -83,6 +90,8 @@ func NewPrecompile(bankKeeper pcommon.BankKeeper, evmKeeper pcommon.EVMKeeper) ( p.SendNativeID = m.ID case BalanceMethod: p.BalanceID = m.ID + case AllBalancesMethod: + p.AllBalancesID = m.ID case NameMethod: p.NameID = m.ID case SymbolMethod: @@ -130,6 +139,8 @@ func (p Precompile) Run(evm *vm.EVM, caller common.Address, callingContract comm return p.sendNative(ctx, method, args, caller, callingContract, value, readOnly) case BalanceMethod: return p.balance(ctx, method, args, value) + case AllBalancesMethod: + return p.all_balances(ctx, method, args, value) case NameMethod: return p.name(ctx, method, args, value) case SymbolMethod: @@ -245,6 +256,35 @@ func (p Precompile) balance(ctx sdk.Context, method *abi.Method, args []interfac return method.Outputs.Pack(p.bankKeeper.GetBalance(ctx, addr, denom).Amount.BigInt()) } +func (p Precompile) all_balances(ctx sdk.Context, method *abi.Method, args []interface{}, value *big.Int) ([]byte, error) { + if err := pcommon.ValidateNonPayable(value); err != nil { + return nil, err + } + + if err := pcommon.ValidateArgsLength(args, 1); err != nil { + return nil, err + } + + addr, err := p.accAddressFromArg(ctx, args[0]) + if err != nil { + return nil, err + } + + coins := p.bankKeeper.GetAllBalances(ctx, addr) + + // convert to coin balance structs + coinBalances := make([]CoinBalance, 0, len(coins)) + + for _, coin := range coins { + coinBalances = append(coinBalances, CoinBalance{ + Amount: coin.Amount.BigInt(), + Denom: coin.Denom, + }) + } + + return method.Outputs.Pack(coinBalances) +} + func (p Precompile) name(ctx sdk.Context, method *abi.Method, args []interface{}, value *big.Int) ([]byte, error) { if err := pcommon.ValidateNonPayable(value); err != nil { return nil, err diff --git a/precompiles/bank/bank_test.go b/precompiles/bank/bank_test.go index c4a16dd8b..6e2e4b328 100644 --- a/precompiles/bank/bank_test.go +++ b/precompiles/bank/bank_test.go @@ -34,7 +34,11 @@ func TestRun(t *testing.T) { testPrivHex := hex.EncodeToString(privKey.Bytes()) senderAddr, senderEVMAddr := testkeeper.PrivateKeyToAddresses(privKey) k.SetAddressMapping(ctx, senderAddr, senderEVMAddr) - err := k.BankKeeper().MintCoins(ctx, types.ModuleName, sdk.NewCoins(sdk.NewCoin("usei", sdk.NewInt(10000000)))) + err := k.BankKeeper().MintCoins(ctx, types.ModuleName, sdk.NewCoins(sdk.NewCoin("ufoo", sdk.NewInt(10000000)))) + require.Nil(t, err) + err = k.BankKeeper().SendCoinsFromModuleToAccount(ctx, types.ModuleName, senderAddr, sdk.NewCoins(sdk.NewCoin("ufoo", sdk.NewInt(10000000)))) + require.Nil(t, err) + err = k.BankKeeper().MintCoins(ctx, types.ModuleName, sdk.NewCoins(sdk.NewCoin("usei", sdk.NewInt(10000000)))) require.Nil(t, err) err = k.BankKeeper().SendCoinsFromModuleToAccount(ctx, types.ModuleName, senderAddr, sdk.NewCoins(sdk.NewCoin("usei", sdk.NewInt(10000000)))) require.Nil(t, err) @@ -164,6 +168,31 @@ func TestRun(t *testing.T) { weiBalance := k.BankKeeper().GetWeiBalance(ctx, seiAddr) require.Equal(t, big.NewInt(100), weiBalance.BigInt()) + // test get all balances + allBalances, err := p.ABI.MethodById(p.AllBalancesID) + require.Nil(t, err) + args, err = allBalances.Inputs.Pack(senderEVMAddr) + require.Nil(t, err) + precompileRes, err = p.Run(&evm, common.Address{}, common.Address{}, append(p.AllBalancesID, args...), nil, false) + require.Nil(t, err) + balances, err := allBalances.Outputs.Unpack(precompileRes) + require.Nil(t, err) + require.Equal(t, 1, len(balances)) + parsedBalances := balances[0].([]struct { + Amount *big.Int `json:"amount"` + Denom string `json:"denom"` + }) + + require.Equal(t, 2, len(parsedBalances)) + require.Equal(t, bank.CoinBalance{ + Amount: big.NewInt(10000000), + Denom: "ufoo", + }, bank.CoinBalance(parsedBalances[0])) + require.Equal(t, bank.CoinBalance{ + Amount: big.NewInt(9999989), + Denom: "usei", + }, bank.CoinBalance(parsedBalances[1])) + // Verify errors properly raised on bank balance calls with incorrect inputs _, err = p.Run(&evm, common.Address{}, common.Address{}, append(p.BalanceID, args[:1]...), nil, false) require.NotNil(t, err) diff --git a/precompiles/common/expected_keepers.go b/precompiles/common/expected_keepers.go index f0525a1b2..854aa7d33 100644 --- a/precompiles/common/expected_keepers.go +++ b/precompiles/common/expected_keepers.go @@ -16,6 +16,7 @@ type BankKeeper interface { SendCoins(sdk.Context, sdk.AccAddress, sdk.AccAddress, sdk.Coins) error SendCoinsAndWei(ctx sdk.Context, from sdk.AccAddress, to sdk.AccAddress, amt sdk.Int, wei sdk.Int) error GetBalance(sdk.Context, sdk.AccAddress, string) sdk.Coin + GetAllBalances(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins GetWeiBalance(ctx sdk.Context, addr sdk.AccAddress) sdk.Int GetDenomMetaData(ctx sdk.Context, denom string) (banktypes.Metadata, bool) GetSupply(ctx sdk.Context, denom string) sdk.Coin From c125f6fab75d9c3c223e244ec151188cd8417a25 Mon Sep 17 00:00:00 2001 From: codchen Date: Fri, 12 Apr 2024 11:13:05 +0800 Subject: [PATCH 07/17] Add ante error handler for EVM msgs (#1535) --- app/ante.go | 1 + app/ante_test.go | 52 +++++++++++++++++++++++++++++++++++++++++++++ x/evm/ante/error.go | 40 ++++++++++++++++++++++++++++++++++ 3 files changed, 93 insertions(+) create mode 100644 x/evm/ante/error.go diff --git a/app/ante.go b/app/ante.go index 905420a68..c032723b0 100644 --- a/app/ante.go +++ b/app/ante.go @@ -121,6 +121,7 @@ func NewAnteHandlerAndDepGenerator(options HandlerOptions) (sdk.AnteHandler, sdk sdk.DefaultWrappedAnteDecorator(evmante.NewGasLimitDecorator(options.EVMKeeper)), } evmAnteHandler, evmAnteDepGenerator := sdk.ChainAnteDecorators(evmAnteDecorators...) + evmAnteHandler = evmante.NewAnteErrorHandler(evmAnteHandler, options.EVMKeeper).Handle router := evmante.NewEVMRouterDecorator(anteHandler, evmAnteHandler, anteDepGenerator, evmAnteDepGenerator) diff --git a/app/ante_test.go b/app/ante_test.go index 0b0ab4ed6..91b6bc932 100644 --- a/app/ante_test.go +++ b/app/ante_test.go @@ -2,6 +2,9 @@ package app_test import ( "context" + "crypto/sha256" + "encoding/hex" + "math/big" "testing" wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types" @@ -18,11 +21,18 @@ import ( "github.com/cosmos/cosmos-sdk/utils/tracing" "github.com/cosmos/cosmos-sdk/x/auth/ante" xauthsigning "github.com/cosmos/cosmos-sdk/x/auth/signing" + ethtypes "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/crypto" aclutils "github.com/sei-protocol/sei-chain/aclmapping/utils" app "github.com/sei-protocol/sei-chain/app" "github.com/sei-protocol/sei-chain/app/apptesting" + testkeeper "github.com/sei-protocol/sei-chain/testutil/keeper" + "github.com/sei-protocol/sei-chain/x/evm/types" + evmtypes "github.com/sei-protocol/sei-chain/x/evm/types" + "github.com/sei-protocol/sei-chain/x/evm/types/ethtx" "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" + abci "github.com/tendermint/tendermint/abci/types" "go.opentelemetry.io/otel" ) @@ -212,3 +222,45 @@ func (suite *AnteTestSuite) TestValidateDepedencies() { suite.Require().Nil(err, "ValidateBasicDecorator ran on ReCheck") } + +func TestEvmAnteErrorHandler(t *testing.T) { + ctx := testkeeper.EVMTestApp.GetContextForDeliverTx([]byte{}) + privKey := testkeeper.MockPrivateKey() + testPrivHex := hex.EncodeToString(privKey.Bytes()) + key, _ := crypto.HexToECDSA(testPrivHex) + txData := ethtypes.LegacyTx{ + GasPrice: big.NewInt(1000000000000), + Gas: 200000, + To: nil, + Value: big.NewInt(0), + Data: []byte{}, + Nonce: 1, // will cause ante error + } + chainID := testkeeper.EVMTestApp.EvmKeeper.ChainID(ctx) + chainCfg := evmtypes.DefaultChainConfig() + ethCfg := chainCfg.EthereumConfig(chainID) + blockNum := big.NewInt(ctx.BlockHeight()) + signer := ethtypes.MakeSigner(ethCfg, blockNum, uint64(ctx.BlockTime().Unix())) + tx, err := ethtypes.SignTx(ethtypes.NewTx(&txData), signer, key) + require.Nil(t, err) + txwrapper, err := ethtx.NewLegacyTx(tx) + require.Nil(t, err) + req, err := types.NewMsgEVMTransaction(txwrapper) + require.Nil(t, err) + builder := testkeeper.EVMTestApp.GetTxConfig().NewTxBuilder() + builder.SetMsgs(req) + txToSend := builder.GetTx() + encodedTx, err := testkeeper.EVMTestApp.GetTxConfig().TxEncoder()(txToSend) + require.Nil(t, err) + + addr, _ := testkeeper.PrivateKeyToAddresses(privKey) + testkeeper.EVMTestApp.BankKeeper.AddCoins(ctx, addr, sdk.NewCoins(sdk.NewCoin("usei", sdk.NewInt(100000000000))), true) + res := testkeeper.EVMTestApp.DeliverTx(ctx, abci.RequestDeliverTx{Tx: encodedTx}, txToSend, sha256.Sum256(encodedTx)) + require.NotEqual(t, 0, res.Code) + testkeeper.EVMTestApp.EvmKeeper.SetTxResults([]*abci.ExecTxResult{{ + Code: res.Code, + }}) + deferredInfo := testkeeper.EVMTestApp.EvmKeeper.GetEVMTxDeferredInfo(ctx) + require.Equal(t, 1, len(deferredInfo)) + require.Equal(t, "incorrect account sequence", deferredInfo[0].Error) +} diff --git a/x/evm/ante/error.go b/x/evm/ante/error.go new file mode 100644 index 000000000..d1d7ab5a6 --- /dev/null +++ b/x/evm/ante/error.go @@ -0,0 +1,40 @@ +package ante + +import ( + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + ethtypes "github.com/ethereum/go-ethereum/core/types" + "github.com/sei-protocol/sei-chain/x/evm/keeper" + "github.com/sei-protocol/sei-chain/x/evm/types" + "github.com/sei-protocol/sei-chain/x/evm/types/ethtx" +) + +type AnteErrorHandler struct { + wrapped sdk.AnteHandler + k *keeper.Keeper +} + +func NewAnteErrorHandler(wrapped sdk.AnteHandler, k *keeper.Keeper) *AnteErrorHandler { + return &AnteErrorHandler{wrapped: wrapped, k: k} +} + +// if there is any error in ante handler, record it in deferred info so that a receipt +// can be written for it in the EndBlock. (we can't directly write receipt here since +// we still need to return an error which will cause any write here to revert) +func (a *AnteErrorHandler) Handle(ctx sdk.Context, tx sdk.Tx, simulate bool) (newCtx sdk.Context, err error) { + newCtx, err = a.wrapped(ctx, tx, simulate) + if err != nil && !ctx.IsCheckTx() && !ctx.IsReCheckTx() && !simulate { + msg := types.MustGetEVMTransactionMessage(tx) + txData, unpackerr := types.UnpackTxData(msg.Data) + if unpackerr != nil { + ctx.Logger().Error(fmt.Sprintf("failed to unpack message data %X", msg.Data.Value)) + return + } + if _, ok := txData.(*ethtx.AssociateTx); ok { + return + } + a.k.AppendErrorToEvmTxDeferredInfo(ctx, ethtypes.NewTx(txData.AsEthereumData()).Hash(), err.Error()) + } + return +} From 51f7ac0775985e05ae4422daa969b1e5ec8d5166 Mon Sep 17 00:00:00 2001 From: Yiming Zang <50607998+yzang2019@users.noreply.github.com> Date: Fri, 12 Apr 2024 23:33:42 +0800 Subject: [PATCH 08/17] Fix unit test (#1540) Fix uni test for state.GetCoinbaseAddress --- x/evm/state/utils_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x/evm/state/utils_test.go b/x/evm/state/utils_test.go index 37b1c2414..286e633a8 100644 --- a/x/evm/state/utils_test.go +++ b/x/evm/state/utils_test.go @@ -10,7 +10,7 @@ import ( func TestGetCoinbaseAddress(t *testing.T) { coinbaseAddr := state.GetCoinbaseAddress(1) - require.Equal(t, coinbaseAddr, "sei1v4mx6hmrda5kucnpwdjsqqqqqqqqqqqpz6djs7") + require.Equal(t, coinbaseAddr.String(), "sei1v4mx6hmrda5kucnpwdjsqqqqqqqqqqqpz6djs7") } func TestSplitUseiWeiAmount(t *testing.T) { From a34deba430e75d440859be3b9c11669f299440ef Mon Sep 17 00:00:00 2001 From: Philip Su Date: Fri, 12 Apr 2024 08:43:07 -0700 Subject: [PATCH 09/17] V4.1.8 evm devnet release 2 (#1517) Add upgrade handler for new version --- app/upgrades.go | 1 + 1 file changed, 1 insertion(+) diff --git a/app/upgrades.go b/app/upgrades.go index 2d31840ea..5ab0017cc 100644 --- a/app/upgrades.go +++ b/app/upgrades.go @@ -86,6 +86,7 @@ var upgradesList = []string{ "v4.1.5-evm-devnet", "v4.1.6-evm-devnet", "v4.1.7-evm-devnet", + "v4.1.8-evm-devnet", } // if there is an override list, use that instead, for integration tests From ac8be0d70480fc3fbebf6fc02baa69af7d0f248e Mon Sep 17 00:00:00 2001 From: Philip Su Date: Fri, 12 Apr 2024 10:54:08 -0700 Subject: [PATCH 10/17] Add x/evm/types unit tests (#1537) --- x/evm/types/keys_test.go | 44 ++++++++++ x/evm/types/message_evm_transaction_test.go | 90 ++++++++++++++++++++- x/evm/types/message_send_test.go | 31 +++++++ x/evm/types/params.go | 2 +- x/evm/types/params_test.go | 37 +++++++++ 5 files changed, 201 insertions(+), 3 deletions(-) create mode 100644 x/evm/types/keys_test.go create mode 100644 x/evm/types/message_send_test.go diff --git a/x/evm/types/keys_test.go b/x/evm/types/keys_test.go new file mode 100644 index 000000000..259a4db27 --- /dev/null +++ b/x/evm/types/keys_test.go @@ -0,0 +1,44 @@ +package types_test + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/sei-protocol/sei-chain/x/evm/types" + "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/stretchr/testify/require" +) + +func TestEVMAddressToSeiAddressKey(t *testing.T) { + evmAddr := common.HexToAddress("0x1234567890abcdef1234567890abcdef12345678") + expectedPrefix := types.EVMAddressToSeiAddressKeyPrefix + key := types.EVMAddressToSeiAddressKey(evmAddr) + + require.Equal(t, expectedPrefix[0], key[0], "Key prefix for evm address to sei address key is incorrect") + require.Equal(t, append(expectedPrefix, evmAddr.Bytes()...), key, "Generated key format is incorrect") +} + +func TestSeiAddressToEVMAddressKey(t *testing.T) { + seiAddr := sdk.AccAddress("sei1234567890abcdef1234567890abcdef12345678") + expectedPrefix := types.SeiAddressToEVMAddressKeyPrefix + key := types.SeiAddressToEVMAddressKey(seiAddr) + + require.Equal(t, expectedPrefix[0], key[0], "Key prefix for sei address to evm address key is incorrect") + require.Equal(t, append(expectedPrefix, seiAddr...), key, "Generated key format is incorrect") +} + +func TestStateKey(t *testing.T) { + evmAddr := common.HexToAddress("0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef") + expectedPrefix := types.StateKeyPrefix + key := types.StateKey(evmAddr) + + require.Equal(t, expectedPrefix[0], key[0], "Key prefix for state key is incorrect") + require.Equal(t, append(expectedPrefix, evmAddr.Bytes()...), key, "Generated key format is incorrect") +} + +func TestBlockBloomKey(t *testing.T) { + height := int64(123456) + key := types.BlockBloomKey(height) + + require.Equal(t, types.BlockBloomPrefix[0], key[0], "Key prefix for block bloom key is incorrect") +} diff --git a/x/evm/types/message_evm_transaction_test.go b/x/evm/types/message_evm_transaction_test.go index 225277d5e..4303f4c78 100644 --- a/x/evm/types/message_evm_transaction_test.go +++ b/x/evm/types/message_evm_transaction_test.go @@ -1,6 +1,14 @@ package types_test import ( + "encoding/hex" + wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types" + sdk "github.com/cosmos/cosmos-sdk/types" + ethtypes "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/crypto" + "github.com/sei-protocol/sei-chain/app" + testkeeper "github.com/sei-protocol/sei-chain/testutil/keeper" + "math/big" "testing" "github.com/ethereum/go-ethereum/common" @@ -11,9 +19,87 @@ import ( ) func TestIsAssociate(t *testing.T) { - msg, err := types.NewMsgEVMTransaction(ðtx.AssociateTx{}) + tx, err := types.NewMsgEVMTransaction(ðtx.AssociateTx{}) require.Nil(t, err) - require.True(t, msg.IsAssociateTx()) + require.True(t, tx.IsAssociateTx()) +} + +func TestIsNotAssociate(t *testing.T) { + tx, err := types.NewMsgEVMTransaction(nil) + require.Error(t, err) + + tx, err = types.NewMsgEVMTransaction(ðtx.AccessTuple{}) + require.Nil(t, err) + require.False(t, tx.IsAssociateTx()) +} + +func TestAsTransaction(t *testing.T) { + k, ctx := testkeeper.MockEVMKeeper() + chainID := k.ChainID(ctx) + chainCfg := types.DefaultChainConfig() + ethCfg := chainCfg.EthereumConfig(chainID) + blockNum := big.NewInt(ctx.BlockHeight()) + privKey := testkeeper.MockPrivateKey() + testPrivHex := hex.EncodeToString(privKey.Bytes()) + key, _ := crypto.HexToECDSA(testPrivHex) + to := new(common.Address) + txData := ethtypes.DynamicFeeTx{ + Nonce: 1, + GasFeeCap: big.NewInt(10000000000000), + Gas: 1000, + To: to, + Value: big.NewInt(1000000000000000), + Data: []byte("abc"), + ChainID: chainID, + } + + signer := ethtypes.MakeSigner(ethCfg, blockNum, uint64(ctx.BlockTime().Unix())) + tx, err := ethtypes.SignTx(ethtypes.NewTx(&txData), signer, key) + typedTx, err := ethtx.NewDynamicFeeTx(tx) + msg, err := types.NewMsgEVMTransaction(typedTx) + require.Nil(t, err) + ethTx, ethTxData := msg.AsTransaction() + require.Equal(t, chainID, ethTx.ChainId()) + require.Equal(t, uint64(1), ethTx.Nonce()) + require.Equal(t, []byte("abc"), ethTx.Data()) + require.Nil(t, ethTxData.Validate()) + +} + +func TestMustGetEVMTransactionMessage(t *testing.T) { + testMsg := types.MsgEVMTransaction{ + Data: nil, + Derived: nil, + } + testTx := app.NewTestTx([]sdk.Msg{&testMsg}) + + types.MustGetEVMTransactionMessage(testTx) +} + +func TestMustGetEVMTransactionMessageWrongType(t *testing.T) { + + // Non-EVM tx + testMsg := wasmtypes.MsgExecuteContract{ + Contract: "sei1y3pxq5dp900czh0mkudhjdqjq5m8cpmmps8yjw", + Msg: []byte("{\"xyz\":{}}"), + } + testTx := app.NewTestTx([]sdk.Msg{&testMsg}) + + defer func() { recover() }() + types.MustGetEVMTransactionMessage(testTx) + t.Errorf("Should not be able to convert a non evm emssage") +} + +func TestMustGetEVMTransactionMessageMultipleMsgs(t *testing.T) { + testMsg := types.MsgEVMTransaction{ + Data: nil, + Derived: nil, + } + testTx := app.NewTestTx([]sdk.Msg{&testMsg, &testMsg}) + + defer func() { recover() }() + types.MustGetEVMTransactionMessage(testTx) + t.Errorf("Should not be able to convert a non evm emssage") } func TestAttackerUnableToSetDerived(t *testing.T) { diff --git a/x/evm/types/message_send_test.go b/x/evm/types/message_send_test.go new file mode 100644 index 000000000..44bcdedf2 --- /dev/null +++ b/x/evm/types/message_send_test.go @@ -0,0 +1,31 @@ +package types_test + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/ethereum/go-ethereum/common" + "testing" + + "github.com/sei-protocol/sei-chain/x/evm/types" + "github.com/stretchr/testify/require" +) + +func TestMessageSendValidate(t *testing.T) { + fromAddr, err := sdk.AccAddressFromBech32("sei1yezq49upxhunjjhudql2fnj5dgvcwjj87pn2wx") + require.Nil(t, err) + msg := types.NewMsgSend(fromAddr, common.HexToAddress("to"), sdk.Coins{sdk.Coin{ + Denom: "sei", + Amount: sdk.NewInt(1), + }}) + require.Nil(t, msg.ValidateBasic()) + + // No coins + msg = types.NewMsgSend(fromAddr, common.HexToAddress("to"), sdk.Coins{}) + require.Error(t, msg.ValidateBasic()) + + // Negative coins + msg = types.NewMsgSend(fromAddr, common.HexToAddress("to"), sdk.Coins{sdk.Coin{ + Denom: "sei", + Amount: sdk.NewInt(-1), + }}) + require.Error(t, msg.ValidateBasic()) +} diff --git a/x/evm/types/params.go b/x/evm/types/params.go index c1b16ed62..da1f1de8a 100644 --- a/x/evm/types/params.go +++ b/x/evm/types/params.go @@ -125,7 +125,7 @@ func validateChainID(i interface{}) error { } if v.IsNegative() { - return fmt.Errorf("negative min fee per gas: %d", v) + return fmt.Errorf("negative chain ID: %d", v) } return nil diff --git a/x/evm/types/params_test.go b/x/evm/types/params_test.go index 839cb88d8..99218af7c 100644 --- a/x/evm/types/params_test.go +++ b/x/evm/types/params_test.go @@ -1,6 +1,7 @@ package types_test import ( + sdk "github.com/cosmos/cosmos-sdk/types" "testing" "github.com/sei-protocol/sei-chain/x/evm/types" @@ -18,3 +19,39 @@ func TestDefaultParams(t *testing.T) { require.Nil(t, types.DefaultParams().Validate()) } + +func TestValidateParamsInvalidPriorityNormalizer(t *testing.T) { + params := types.DefaultParams() + params.PriorityNormalizer = sdk.NewDec(-1) // Set to invalid negative value + + err := params.Validate() + require.Error(t, err) + require.Contains(t, err.Error(), "nonpositive priority normalizer") +} + +func TestValidateParamsNegativeBaseFeePerGas(t *testing.T) { + params := types.DefaultParams() + params.BaseFeePerGas = sdk.NewDec(-1) // Set to invalid negative value + + err := params.Validate() + require.Error(t, err) + require.Contains(t, err.Error(), "negative base fee per gas") +} + +func TestValidateParamsNegativeChainID(t *testing.T) { + params := types.DefaultParams() + params.ChainId = sdk.NewInt(-1) // Set to invalid negative value + + err := params.Validate() + require.Error(t, err) + require.Contains(t, err.Error(), "negative chain ID") +} + +func TestBaseFeeMinimumFee(t *testing.T) { + params := types.DefaultParams() + params.MinimumFeePerGas = sdk.NewDec(1) + params.BaseFeePerGas = params.MinimumFeePerGas.Add(sdk.NewDec(1)) + err := params.Validate() + require.Error(t, err) + require.Contains(t, err.Error(), "minimum fee cannot be lower than base fee") +} From 2f9f8f51c0e63f99dbccaf096b93ad76d25dc665 Mon Sep 17 00:00:00 2001 From: Kartik Bhat Date: Sun, 14 Apr 2024 22:16:28 -0400 Subject: [PATCH 11/17] Bump SeiDB (Seiv2) (#1542) Bump Seidb --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index a5c04de9f..a4ce0324d 100644 --- a/go.mod +++ b/go.mod @@ -351,7 +351,7 @@ replace ( github.com/cosmos/ibc-go/v3 => github.com/sei-protocol/sei-ibc-go/v3 v3.3.0 github.com/ethereum/go-ethereum => github.com/sei-protocol/go-ethereum v1.13.5-sei-13 github.com/gogo/protobuf => github.com/regen-network/protobuf v1.3.3-alpha.regen.1 - github.com/sei-protocol/sei-db => github.com/sei-protocol/sei-db v0.0.33 + github.com/sei-protocol/sei-db => github.com/sei-protocol/sei-db v0.0.35 // Latest goleveldb is broken, we have to stick to this version github.com/syndtr/goleveldb => github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 github.com/tendermint/tendermint => github.com/sei-protocol/sei-tendermint v0.2.40-seiv2 diff --git a/go.sum b/go.sum index 55dc77b06..1b2828a7d 100644 --- a/go.sum +++ b/go.sum @@ -1349,8 +1349,8 @@ github.com/sei-protocol/goutils v0.0.2 h1:Bfa7Sv+4CVLNM20QcpvGb81B8C5HkQC/kW1CQp github.com/sei-protocol/goutils v0.0.2/go.mod h1:iYE2DuJfEnM+APPehr2gOUXfuLuPsVxorcDO+Tzq9q8= github.com/sei-protocol/sei-cosmos v0.2.80-seiv2 h1:stu0hTZmQWvewzr/y40iZrKsKHFuCXFKNEJGsgivvL4= github.com/sei-protocol/sei-cosmos v0.2.80-seiv2/go.mod h1:ib/gp0gCxN7FXUZ40j5+x8BeyoI7AcX+rTvf53JoDsY= -github.com/sei-protocol/sei-db v0.0.33 h1:TspNkw/lW7fubR0TsOpmJdzWiLecMDOS5DAxFNQXQ6M= -github.com/sei-protocol/sei-db v0.0.33/go.mod h1:F/ZKZA8HJPcUzSZPA8yt6pfwlGriJ4RDR4eHKSGLStI= +github.com/sei-protocol/sei-db v0.0.35 h1:BNHv0gtKE4J5kq1Mhxt9dpop3lI4W2I5WurgWYIYa4E= +github.com/sei-protocol/sei-db v0.0.35/go.mod h1:F/ZKZA8HJPcUzSZPA8yt6pfwlGriJ4RDR4eHKSGLStI= github.com/sei-protocol/sei-iavl v0.1.9 h1:y4mVYftxLNRs6533zl7N0/Ch+CzRQc04JDfHolIxgBE= github.com/sei-protocol/sei-iavl v0.1.9/go.mod h1:7PfkEVT5dcoQE+s/9KWdoXJ8VVVP1QpYYPLdxlkSXFk= github.com/sei-protocol/sei-ibc-go/v3 v3.3.0 h1:/mjpTuCSEVDJ51nUDSHU92N0bRSwt49r1rmdC/lqgp8= From 78eb1d663346ca557292cbc4d3891278deacf456 Mon Sep 17 00:00:00 2001 From: codchen Date: Mon, 15 Apr 2024 14:09:45 +0800 Subject: [PATCH 12/17] Disallow unassociated EOA addresses from using precompiles (#1538) * Disallow unassociated EOA addresses from using precompiles * tests --- contracts/test/EVMPrecompileTester.js | 24 ++++++-- precompiles/addr/addr.go | 14 ++++- precompiles/bank/bank.go | 6 +- precompiles/common/expected_keepers.go | 3 +- precompiles/distribution/distribution.go | 11 +++- precompiles/gov/gov.go | 11 +++- precompiles/gov/gov_test.go | 12 ++-- precompiles/ibc/ibc.go | 6 +- precompiles/wasmd/wasmd.go | 12 +++- precompiles/wasmd/wasmd_test.go | 6 +- x/evm/artifacts/native/artifacts_test.go | 15 +++-- x/evm/client/wasm/query.go | 78 +++++++++++++----------- x/evm/client/wasm/query_test.go | 29 ++++++--- x/evm/keeper/address.go | 8 --- x/evm/keeper/evm.go | 7 +++ x/evm/state/utils_test.go | 4 +- 16 files changed, 161 insertions(+), 85 deletions(-) diff --git a/contracts/test/EVMPrecompileTester.js b/contracts/test/EVMPrecompileTester.js index cf16772be..34551f898 100644 --- a/contracts/test/EVMPrecompileTester.js +++ b/contracts/test/EVMPrecompileTester.js @@ -30,12 +30,25 @@ describe("EVM Test", function () { // Get a contract instance erc20 = new ethers.Contract(contractAddress, contractABI, signer); + + // force association on owner2 + const tx1 = await signer.sendTransaction({ + to: owner2, + value: 100000000000000 + }); + const receipt1 = await tx1.wait(); + expect(receipt1.status).to.equal(1); + const tx2 = await signer2.sendTransaction({ + to: owner, + value: 1 + }); + const receipt2 = await tx2.wait(); + expect(receipt2.status).to.equal(1); }); it("Transfer function", async function() { - const receiver = '0x70997970C51812dc3A010C7d01b50e0d17dc79C8'; const beforeBalance = await erc20.balanceOf(owner); - const tx = await erc20.transfer(receiver, 1); + const tx = await erc20.transfer(owner2, 1); const receipt = await tx.wait(); expect(receipt.status).to.equal(1); const afterBalance = await erc20.balanceOf(owner); @@ -56,7 +69,6 @@ describe("EVM Test", function () { }); it("Approve and TransferFrom functions", async function() { - const receiver = '0x70997970C51812dc3A010C7d01b50e0d17dc79C8'; // lets have owner approve the transfer and have owner2 do the transferring const approvalAmount = await erc20.allowance(owner, owner2); expect(approvalAmount).to.equal(0); @@ -69,13 +81,13 @@ describe("EVM Test", function () { // transfer from owner to owner2 - const balanceBefore = await erc20.balanceOf(receiver); - const transferFromTx = await erc20AsOwner2.transferFrom(owner, receiver, 100); + const balanceBefore = await erc20.balanceOf(owner2); + const transferFromTx = await erc20AsOwner2.transferFrom(owner, owner2, 100); // await sleep(3000); const transferFromReceipt = await transferFromTx.wait(); expect(transferFromReceipt.status).to.equal(1); - const balanceAfter = await erc20.balanceOf(receiver); + const balanceAfter = await erc20.balanceOf(owner2); const diff = balanceAfter - balanceBefore; expect(diff).to.equal(100); }); diff --git a/precompiles/addr/addr.go b/precompiles/addr/addr.go index f78a33453..aff5b06c7 100644 --- a/precompiles/addr/addr.go +++ b/precompiles/addr/addr.go @@ -112,8 +112,11 @@ func (p Precompile) getSeiAddr(ctx sdk.Context, method *abi.Method, args []inter return nil, err } - seiAddrStr := p.evmKeeper.GetSeiAddressOrDefault(ctx, args[0].(common.Address)).String() - return method.Outputs.Pack(seiAddrStr) + seiAddr, found := p.evmKeeper.GetSeiAddress(ctx, args[0].(common.Address)) + if !found { + return nil, fmt.Errorf("EVM address %s is not associated", args[0].(common.Address).Hex()) + } + return method.Outputs.Pack(seiAddr.String()) } func (p Precompile) getEvmAddr(ctx sdk.Context, method *abi.Method, args []interface{}, value *big.Int) ([]byte, error) { @@ -125,10 +128,15 @@ func (p Precompile) getEvmAddr(ctx sdk.Context, method *abi.Method, args []inter return nil, err } - evmAddr, err := p.evmKeeper.GetEVMAddressFromBech32OrDefault(ctx, args[0].(string)) + seiAddr, err := sdk.AccAddressFromBech32(args[0].(string)) if err != nil { return nil, err } + + evmAddr, found := p.evmKeeper.GetEVMAddress(ctx, seiAddr) + if !found { + return nil, fmt.Errorf("sei address %s is not associated", args[0].(string)) + } return method.Outputs.Pack(evmAddr) } diff --git a/precompiles/bank/bank.go b/precompiles/bank/bank.go index 395cbd6e1..c31b7e2f0 100644 --- a/precompiles/bank/bank.go +++ b/precompiles/bank/bank.go @@ -347,7 +347,11 @@ func (p Precompile) accAddressFromArg(ctx sdk.Context, arg interface{}) (sdk.Acc if addr == (common.Address{}) { return nil, errors.New("invalid addr") } - return p.evmKeeper.GetSeiAddressOrDefault(ctx, addr), nil + seiAddr, found := p.evmKeeper.GetSeiAddress(ctx, addr) + if !found { + return nil, fmt.Errorf("EVM address %s is not associated", addr.Hex()) + } + return seiAddr, nil } func (Precompile) IsTransaction(method string) bool { diff --git a/precompiles/common/expected_keepers.go b/precompiles/common/expected_keepers.go index 854aa7d33..3b8596431 100644 --- a/precompiles/common/expected_keepers.go +++ b/precompiles/common/expected_keepers.go @@ -24,9 +24,8 @@ type BankKeeper interface { type EVMKeeper interface { GetSeiAddress(sdk.Context, common.Address) (sdk.AccAddress, bool) - GetSeiAddressOrDefault(ctx sdk.Context, evmAddress common.Address) sdk.AccAddress + GetSeiAddressOrDefault(ctx sdk.Context, evmAddress common.Address) sdk.AccAddress // only used for getting precompile Sei addresses GetEVMAddress(sdk.Context, sdk.AccAddress) (common.Address, bool) - GetEVMAddressFromBech32OrDefault(ctx sdk.Context, seiAddress string) (common.Address, error) GetCodeHash(sdk.Context, common.Address) common.Hash GetPriorityNormalizer(ctx sdk.Context) sdk.Dec GetBaseDenom(ctx sdk.Context) string diff --git a/precompiles/distribution/distribution.go b/precompiles/distribution/distribution.go index d93e5683c..33dfb3533 100644 --- a/precompiles/distribution/distribution.go +++ b/precompiles/distribution/distribution.go @@ -4,6 +4,7 @@ import ( "bytes" "embed" "errors" + "fmt" "math/big" sdk "github.com/cosmos/cosmos-sdk/types" @@ -124,7 +125,10 @@ func (p Precompile) setWithdrawAddress(ctx sdk.Context, method *abi.Method, call if err := pcommon.ValidateArgsLength(args, 1); err != nil { return nil, err } - delegator := p.evmKeeper.GetSeiAddressOrDefault(ctx, caller) + delegator, found := p.evmKeeper.GetSeiAddress(ctx, caller) + if !found { + return nil, fmt.Errorf("delegator %s is not associated", caller.Hex()) + } withdrawAddr, err := p.accAddressFromArg(ctx, args[0]) if err != nil { return nil, err @@ -144,7 +148,10 @@ func (p Precompile) withdrawDelegationRewards(ctx sdk.Context, method *abi.Metho if err := pcommon.ValidateArgsLength(args, 1); err != nil { return nil, err } - delegator := p.evmKeeper.GetSeiAddressOrDefault(ctx, caller) + delegator, found := p.evmKeeper.GetSeiAddress(ctx, caller) + if !found { + return nil, fmt.Errorf("delegator %s is not associated", caller.Hex()) + } validator, err := sdk.ValAddressFromBech32(args[0].(string)) if err != nil { return nil, err diff --git a/precompiles/gov/gov.go b/precompiles/gov/gov.go index 86ec7e3bd..e80f6f4f4 100644 --- a/precompiles/gov/gov.go +++ b/precompiles/gov/gov.go @@ -4,6 +4,7 @@ import ( "bytes" "embed" "errors" + "fmt" "math/big" sdk "github.com/cosmos/cosmos-sdk/types" @@ -127,7 +128,10 @@ func (p Precompile) vote(ctx sdk.Context, method *abi.Method, caller common.Addr if err := pcommon.ValidateArgsLength(args, 2); err != nil { return nil, err } - voter := p.evmKeeper.GetSeiAddressOrDefault(ctx, caller) + voter, found := p.evmKeeper.GetSeiAddress(ctx, caller) + if !found { + return nil, fmt.Errorf("voter %s is not associated", caller.Hex()) + } proposalID := args[0].(uint64) voteOption := args[1].(int32) err := p.govKeeper.AddVote(ctx, proposalID, voter, govtypes.NewNonSplitVoteOption(govtypes.VoteOption(voteOption))) @@ -141,7 +145,10 @@ func (p Precompile) deposit(ctx sdk.Context, method *abi.Method, caller common.A if err := pcommon.ValidateArgsLength(args, 1); err != nil { return nil, err } - depositor := p.evmKeeper.GetSeiAddressOrDefault(ctx, caller) + depositor, found := p.evmKeeper.GetSeiAddress(ctx, caller) + if !found { + return nil, fmt.Errorf("depositor %s is not associated", caller.Hex()) + } proposalID := args[0].(uint64) if value == nil || value.Sign() == 0 { return nil, errors.New("set `value` field to non-zero to deposit fund") diff --git a/precompiles/gov/gov_test.go b/precompiles/gov/gov_test.go index 522e35c97..9e77c36af 100644 --- a/precompiles/gov/gov_test.go +++ b/precompiles/gov/gov_test.go @@ -57,10 +57,11 @@ func TestVoteDeposit(t *testing.T) { req, err := evmtypes.NewMsgEVMTransaction(txwrapper) require.Nil(t, err) - _, evmAddr := testkeeper.PrivateKeyToAddresses(privKey) + seiAddr, evmAddr := testkeeper.PrivateKeyToAddresses(privKey) + k.SetAddressMapping(ctx, seiAddr, evmAddr) amt := sdk.NewCoins(sdk.NewCoin(k.GetBaseDenom(ctx), sdk.NewInt(200000000))) require.Nil(t, k.BankKeeper().MintCoins(ctx, evmtypes.ModuleName, sdk.NewCoins(sdk.NewCoin(k.GetBaseDenom(ctx), sdk.NewInt(200000000))))) - require.Nil(t, k.BankKeeper().SendCoinsFromModuleToAccount(ctx, evmtypes.ModuleName, evmAddr[:], amt)) + require.Nil(t, k.BankKeeper().SendCoinsFromModuleToAccount(ctx, evmtypes.ModuleName, seiAddr, amt)) msgServer := keeper.NewMsgServerImpl(k) @@ -101,10 +102,11 @@ func TestVoteDeposit(t *testing.T) { req, err := evmtypes.NewMsgEVMTransaction(txwrapper) require.Nil(t, err) - _, evmAddr := testkeeper.PrivateKeyToAddresses(privKey) + seiAddr, evmAddr := testkeeper.PrivateKeyToAddresses(privKey) + k.SetAddressMapping(ctx, seiAddr, evmAddr) amt := sdk.NewCoins(sdk.NewCoin(k.GetBaseDenom(ctx), sdk.NewInt(200000000))) require.Nil(t, k.BankKeeper().MintCoins(ctx, evmtypes.ModuleName, sdk.NewCoins(sdk.NewCoin(k.GetBaseDenom(ctx), sdk.NewInt(200000000))))) - require.Nil(t, k.BankKeeper().SendCoinsFromModuleToAccount(ctx, evmtypes.ModuleName, evmAddr[:], amt)) + require.Nil(t, k.BankKeeper().SendCoinsFromModuleToAccount(ctx, evmtypes.ModuleName, seiAddr, amt)) msgServer := keeper.NewMsgServerImpl(k) @@ -113,7 +115,7 @@ func TestVoteDeposit(t *testing.T) { require.Nil(t, err) require.Empty(t, res.VmError) - v, found := testApp.GovKeeper.GetVote(ctx, proposal.ProposalId, evmAddr[:]) + v, found := testApp.GovKeeper.GetVote(ctx, proposal.ProposalId, seiAddr) require.True(t, found) require.Equal(t, 1, len(v.Options)) require.Equal(t, opt, v.Options[0].Option) diff --git a/precompiles/ibc/ibc.go b/precompiles/ibc/ibc.go index 7fdb9f9d9..51f17b04b 100644 --- a/precompiles/ibc/ibc.go +++ b/precompiles/ibc/ibc.go @@ -256,5 +256,9 @@ func (p Precompile) accAddressFromArg(ctx sdk.Context, arg interface{}) (sdk.Acc if addr == (common.Address{}) { return nil, errors.New("invalid addr") } - return p.evmKeeper.GetSeiAddressOrDefault(ctx, addr), nil + seiAddr, found := p.evmKeeper.GetSeiAddress(ctx, addr) + if !found { + return nil, fmt.Errorf("EVM address %s is not associated", addr.Hex()) + } + return seiAddr, nil } diff --git a/precompiles/wasmd/wasmd.go b/precompiles/wasmd/wasmd.go index 1489d9957..ad77fc3e2 100644 --- a/precompiles/wasmd/wasmd.go +++ b/precompiles/wasmd/wasmd.go @@ -163,7 +163,11 @@ func (p Precompile) instantiate(ctx sdk.Context, method *abi.Method, caller comm // type assertion will always succeed because it's already validated in p.Prepare call in Run() codeID := args[0].(uint64) - creatorAddr := p.evmKeeper.GetSeiAddressOrDefault(ctx, caller) + creatorAddr, found := p.evmKeeper.GetSeiAddress(ctx, caller) + if !found { + rerr = fmt.Errorf("creator %s is not associated", caller.Hex()) + return + } var adminAddr sdk.AccAddress adminAddrStr := args[1].(string) if len(adminAddrStr) > 0 { @@ -255,7 +259,11 @@ func (p Precompile) execute(ctx sdk.Context, method *abi.Method, caller common.A rerr = err return } - senderAddr := p.evmKeeper.GetSeiAddressOrDefault(ctx, caller) + senderAddr, found := p.evmKeeper.GetSeiAddress(ctx, caller) + if !found { + rerr = fmt.Errorf("sender %s is not associated", caller.Hex()) + return + } msg := args[1].([]byte) coins := sdk.NewCoins() coinsBz := args[2].([]byte) diff --git a/precompiles/wasmd/wasmd_test.go b/precompiles/wasmd/wasmd_test.go index 926a007b1..2676802cd 100644 --- a/precompiles/wasmd/wasmd_test.go +++ b/precompiles/wasmd/wasmd_test.go @@ -39,6 +39,7 @@ func TestInstantiate(t *testing.T) { testApp := app.Setup(false, false) mockAddr, mockEVMAddr := testkeeper.MockAddressPair() ctx := testApp.GetContextForDeliverTx([]byte{}).WithBlockTime(time.Now()) + testApp.EvmKeeper.SetAddressMapping(ctx, mockAddr, mockEVMAddr) wasmKeeper := wasmkeeper.NewDefaultPermissionKeeper(testApp.WasmKeeper) p, err := wasmd.NewPrecompile(&testApp.EvmKeeper, wasmKeeper, testApp.WasmKeeper, testApp.BankKeeper) require.Nil(t, err) @@ -70,7 +71,7 @@ func TestInstantiate(t *testing.T) { require.Equal(t, 2, len(outputs)) require.Equal(t, "sei1hrpna9v7vs3stzyd4z3xf00676kf78zpe2u5ksvljswn2vnjp3yslucc3n", outputs[0].(string)) require.Empty(t, outputs[1].([]byte)) - require.Equal(t, uint64(902898), g) + require.Equal(t, uint64(902838), g) // non-existent code ID args, _ = instantiateMethod.Inputs.Pack( @@ -171,8 +172,9 @@ func TestExecute(t *testing.T) { func TestQuery(t *testing.T) { testApp := app.Setup(false, false) - mockAddr, _ := testkeeper.MockAddressPair() + mockAddr, mockEVMAddr := testkeeper.MockAddressPair() ctx := testApp.GetContextForDeliverTx([]byte{}).WithBlockTime(time.Now()) + testApp.EvmKeeper.SetAddressMapping(ctx, mockAddr, mockEVMAddr) wasmKeeper := wasmkeeper.NewDefaultPermissionKeeper(testApp.WasmKeeper) p, err := wasmd.NewPrecompile(&testApp.EvmKeeper, wasmKeeper, testApp.WasmKeeper, testApp.BankKeeper) require.Nil(t, err) diff --git a/x/evm/artifacts/native/artifacts_test.go b/x/evm/artifacts/native/artifacts_test.go index 46451776c..e023def9b 100644 --- a/x/evm/artifacts/native/artifacts_test.go +++ b/x/evm/artifacts/native/artifacts_test.go @@ -22,7 +22,9 @@ import ( func TestSimple(t *testing.T) { bytecode := native.GetBin() abi, err := native.NativeMetaData.GetAbi() + require.Nil(t, err) args, err := abi.Pack("", "test", "TST", "TST", uint8(6)) + require.Nil(t, err) contractData := append(bytecode, args...) testApp := testkeeper.EVMTestApp @@ -51,12 +53,13 @@ func TestSimple(t *testing.T) { req, err := types.NewMsgEVMTransaction(txwrapper) require.Nil(t, err) - _, evmAddr := testkeeper.PrivateKeyToAddresses(privKey) + seiAddr, evmAddr := testkeeper.PrivateKeyToAddresses(privKey) + k.SetAddressMapping(ctx, seiAddr, evmAddr) amt := sdk.NewCoins(sdk.NewCoin(k.GetBaseDenom(ctx), sdk.NewInt(200000000))) require.Nil(t, k.BankKeeper().MintCoins(ctx, types.ModuleName, sdk.NewCoins(sdk.NewCoin(k.GetBaseDenom(ctx), sdk.NewInt(200000000))))) - require.Nil(t, k.BankKeeper().SendCoinsFromModuleToAccount(ctx, types.ModuleName, evmAddr[:], amt)) + require.Nil(t, k.BankKeeper().SendCoinsFromModuleToAccount(ctx, types.ModuleName, seiAddr, amt)) require.Nil(t, k.BankKeeper().MintCoins(ctx, types.ModuleName, sdk.NewCoins(sdk.NewCoin("test", sdk.NewInt(200000000))))) - require.Nil(t, k.BankKeeper().SendCoinsFromModuleToAccount(ctx, types.ModuleName, evmAddr[:], sdk.NewCoins(sdk.NewCoin("test", sdk.NewInt(200000000))))) + require.Nil(t, k.BankKeeper().SendCoinsFromModuleToAccount(ctx, types.ModuleName, seiAddr, sdk.NewCoins(sdk.NewCoin("test", sdk.NewInt(200000000))))) msgServer := keeper.NewMsgServerImpl(k) @@ -70,10 +73,14 @@ func TestSimple(t *testing.T) { require.NotNil(t, receipt) require.Equal(t, uint32(ethtypes.ReceiptStatusSuccessful), receipt.Status) k.SetERC20NativePointer(ctx, "test", common.HexToAddress(receipt.ContractAddress)) + _, found := k.GetSeiAddress(ctx, common.HexToAddress(receipt.ContractAddress)) + require.True(t, found) // send transaction to the contract contractAddr := common.HexToAddress(receipt.ContractAddress) - data, err := abi.Pack("transfer", common.HexToAddress("0x34b575c2eaae50b81375f077517e6490adbd9735"), big.NewInt(1)) + to := common.HexToAddress("0x34b575c2eaae50b81375f077517e6490adbd9735") + k.SetAddressMapping(ctx, sdk.AccAddress(to[:]), to) + data, err := abi.Pack("transfer", to, big.NewInt(1)) require.Nil(t, err) txData = ethtypes.LegacyTx{ GasPrice: big.NewInt(1000000000000), diff --git a/x/evm/client/wasm/query.go b/x/evm/client/wasm/query.go index 8e94e306b..e82334599 100644 --- a/x/evm/client/wasm/query.go +++ b/x/evm/client/wasm/query.go @@ -4,6 +4,7 @@ import ( "encoding/base64" "encoding/json" "errors" + "fmt" "math/big" sdk "github.com/cosmos/cosmos-sdk/types" @@ -40,9 +41,9 @@ func (h *EVMQueryHandler) HandleERC20TransferPayload(ctx sdk.Context, recipient if err != nil { return nil, err } - evmAddr, err := h.k.GetEVMAddressFromBech32OrDefault(ctx, recipient) - if err != nil { - return nil, err + evmAddr, found := h.k.GetEVMAddress(ctx, sdk.MustAccAddressFromBech32(recipient)) + if !found { + return nil, fmt.Errorf("%s is not associated", recipient) } bz, err := abi.Pack("transfer", evmAddr, amount.BigInt()) if err != nil { @@ -129,7 +130,10 @@ func (h *EVMQueryHandler) HandleERC20Balance(ctx sdk.Context, contractAddress st if err != nil { return nil, err } - evmAddr := h.k.GetEVMAddressOrDefault(ctx, addr) + evmAddr, found := h.k.GetEVMAddress(ctx, addr) + if !found { + return nil, fmt.Errorf("address %s is not associated", addr.String()) + } contract := common.HexToAddress(contractAddress) abi, err := native.NativeMetaData.GetAbi() if err != nil { @@ -192,13 +196,13 @@ func (h *EVMQueryHandler) HandleERC721TransferPayload(ctx sdk.Context, from stri if err != nil { return nil, err } - fromEvmAddr, err := h.k.GetEVMAddressFromBech32OrDefault(ctx, from) - if err != nil { - return nil, err + fromEvmAddr, found := h.k.GetEVMAddress(ctx, sdk.MustAccAddressFromBech32(from)) + if !found { + return nil, fmt.Errorf("%s is not associated", from) } - toEvmAddr, err := h.k.GetEVMAddressFromBech32OrDefault(ctx, recipient) - if err != nil { - return nil, err + toEvmAddr, found := h.k.GetEVMAddress(ctx, sdk.MustAccAddressFromBech32(recipient)) + if !found { + return nil, fmt.Errorf("%s is not associated", recipient) } t, ok := sdk.NewIntFromString(tokenId) if !ok { @@ -216,10 +220,11 @@ func (h *EVMQueryHandler) HandleERC721ApprovePayload(ctx sdk.Context, spender st spenderEvmAddr := common.Address{} // empty address if approval should be revoked (i.e. spender string is empty) var err error if spender != "" { - spenderEvmAddr, err = h.k.GetEVMAddressFromBech32OrDefault(ctx, spender) - if err != nil { - return nil, err + evmAddr, found := h.k.GetEVMAddress(ctx, sdk.MustAccAddressFromBech32(spender)) + if !found { + return nil, fmt.Errorf("%s is not associated", spender) } + spenderEvmAddr = evmAddr } abi, err := cw721.Cw721MetaData.GetAbi() if err != nil { @@ -238,9 +243,9 @@ func (h *EVMQueryHandler) HandleERC721ApprovePayload(ctx sdk.Context, spender st } func (h *EVMQueryHandler) HandleERC721SetApprovalAllPayload(ctx sdk.Context, to string, approved bool) ([]byte, error) { - evmAddr, err := h.k.GetEVMAddressFromBech32OrDefault(ctx, to) - if err != nil { - return nil, err + evmAddr, found := h.k.GetEVMAddress(ctx, sdk.MustAccAddressFromBech32(to)) + if !found { + return nil, fmt.Errorf("%s is not associated", to) } abi, err := cw721.Cw721MetaData.GetAbi() if err != nil { @@ -259,13 +264,13 @@ func (h *EVMQueryHandler) HandleERC20TransferFromPayload(ctx sdk.Context, owner if err != nil { return nil, err } - ownerEvmAddr, err := h.k.GetEVMAddressFromBech32OrDefault(ctx, owner) - if err != nil { - return nil, err + ownerEvmAddr, found := h.k.GetEVMAddress(ctx, sdk.MustAccAddressFromBech32(owner)) + if !found { + return nil, fmt.Errorf("%s is not associated", owner) } - recipientEvmAddr, err := h.k.GetEVMAddressFromBech32OrDefault(ctx, recipient) - if err != nil { - return nil, err + recipientEvmAddr, found := h.k.GetEVMAddress(ctx, sdk.MustAccAddressFromBech32(recipient)) + if !found { + return nil, fmt.Errorf("%s is not associated", recipient) } bz, err := abi.Pack("transferFrom", ownerEvmAddr, recipientEvmAddr, amount.BigInt()) if err != nil { @@ -280,9 +285,9 @@ func (h *EVMQueryHandler) HandleERC20ApprovePayload(ctx sdk.Context, spender str if err != nil { return nil, err } - spenderEvmAddr, err := h.k.GetEVMAddressFromBech32OrDefault(ctx, spender) - if err != nil { - return nil, err + spenderEvmAddr, found := h.k.GetEVMAddress(ctx, sdk.MustAccAddressFromBech32(spender)) + if !found { + return nil, fmt.Errorf("%s is not associated", spender) } bz, err := abi.Pack("approve", spenderEvmAddr, amount.BigInt()) @@ -299,12 +304,15 @@ func (h *EVMQueryHandler) HandleERC20Allowance(ctx sdk.Context, contractAddress if err != nil { return nil, err } - ownerEvmAddr := h.k.GetEVMAddressOrDefault(ctx, ownerAddr) + ownerEvmAddr, found := h.k.GetEVMAddress(ctx, ownerAddr) + if !found { + return nil, fmt.Errorf("owner %s is not associated", ownerAddr.String()) + } // Get the evm address of spender - spenderEvmAddr, err := h.k.GetEVMAddressFromBech32OrDefault(ctx, spender) - if err != nil { - return nil, err + spenderEvmAddr, found := h.k.GetEVMAddress(ctx, sdk.MustAccAddressFromBech32(spender)) + if !found { + return nil, fmt.Errorf("%s is not associated", spender) } // Fetch the contract ABI @@ -375,13 +383,13 @@ func (h *EVMQueryHandler) HandleERC721IsApprovedForAll(ctx sdk.Context, caller s if err != nil { return nil, err } - ownerEvmAddr, err := h.k.GetEVMAddressFromBech32OrDefault(ctx, owner) - if err != nil { - return nil, err + ownerEvmAddr, found := h.k.GetEVMAddress(ctx, sdk.MustAccAddressFromBech32(owner)) + if !found { + return nil, fmt.Errorf("%s is not associated", owner) } - operatorEvmAddr, err := h.k.GetEVMAddressFromBech32OrDefault(ctx, operator) - if err != nil { - return nil, err + operatorEvmAddr, found := h.k.GetEVMAddress(ctx, sdk.MustAccAddressFromBech32(operator)) + if !found { + return nil, fmt.Errorf("%s is not associated", operator) } contract := common.HexToAddress(contractAddress) abi, err := cw721.Cw721MetaData.GetAbi() diff --git a/x/evm/client/wasm/query_test.go b/x/evm/client/wasm/query_test.go index 6fc9d12cf..b13618592 100644 --- a/x/evm/client/wasm/query_test.go +++ b/x/evm/client/wasm/query_test.go @@ -13,8 +13,10 @@ import ( func TestERC721TransferPayload(t *testing.T) { k, ctx := testkeeper.MockEVMKeeper() - addr1, _ := testkeeper.MockAddressPair() - addr2, _ := testkeeper.MockAddressPair() + addr1, e1 := testkeeper.MockAddressPair() + addr2, e2 := testkeeper.MockAddressPair() + k.SetAddressMapping(ctx, addr1, e1) + k.SetAddressMapping(ctx, addr2, e2) h := wasm.NewEVMQueryHandler(k) res, err := h.HandleERC721TransferPayload(ctx, addr1.String(), addr2.String(), "1") require.Nil(t, err) @@ -23,7 +25,8 @@ func TestERC721TransferPayload(t *testing.T) { func TestERC721ApprovePayload(t *testing.T) { k, ctx := testkeeper.MockEVMKeeper() - addr1, _ := testkeeper.MockAddressPair() + addr1, e1 := testkeeper.MockAddressPair() + k.SetAddressMapping(ctx, addr1, e1) h := wasm.NewEVMQueryHandler(k) res, err := h.HandleERC721ApprovePayload(ctx, addr1.String(), "1") require.Nil(t, err) @@ -32,7 +35,8 @@ func TestERC721ApprovePayload(t *testing.T) { func TestERC721ApproveAllPayload(t *testing.T) { k, ctx := testkeeper.MockEVMKeeper() - addr1, _ := testkeeper.MockAddressPair() + addr1, e1 := testkeeper.MockAddressPair() + k.SetAddressMapping(ctx, addr1, e1) h := wasm.NewEVMQueryHandler(k) res, err := h.HandleERC721SetApprovalAllPayload(ctx, addr1.String(), true) require.Nil(t, err) @@ -41,7 +45,8 @@ func TestERC721ApproveAllPayload(t *testing.T) { func TestERC20TransferPayload(t *testing.T) { k, ctx := testkeeper.MockEVMKeeper() - addr1, _ := testkeeper.MockAddressPair() + addr1, e1 := testkeeper.MockAddressPair() + k.SetAddressMapping(ctx, addr1, e1) h := wasm.NewEVMQueryHandler(k) value := types.NewInt(500) res, err := h.HandleERC20TransferPayload(ctx, addr1.String(), &value) @@ -51,8 +56,10 @@ func TestERC20TransferPayload(t *testing.T) { func TestERC20TransferFromPayload(t *testing.T) { k, ctx := testkeeper.MockEVMKeeper() - addr1, _ := testkeeper.MockAddressPair() - addr2, _ := testkeeper.MockAddressPair() + addr1, e1 := testkeeper.MockAddressPair() + addr2, e2 := testkeeper.MockAddressPair() + k.SetAddressMapping(ctx, addr1, e1) + k.SetAddressMapping(ctx, addr2, e2) h := wasm.NewEVMQueryHandler(k) value := types.NewInt(500) res, err := h.HandleERC20TransferFromPayload(ctx, addr1.String(), addr2.String(), &value) @@ -62,7 +69,8 @@ func TestERC20TransferFromPayload(t *testing.T) { func TestERC20ApprovePayload(t *testing.T) { k, ctx := testkeeper.MockEVMKeeper() - addr1, _ := testkeeper.MockAddressPair() + addr1, e1 := testkeeper.MockAddressPair() + k.SetAddressMapping(ctx, addr1, e1) h := wasm.NewEVMQueryHandler(k) value := types.NewInt(500) res, err := h.HandleERC20ApprovePayload(ctx, addr1.String(), &value) @@ -75,6 +83,7 @@ func TestGetAddress(t *testing.T) { seiAddr1, evmAddr1 := testkeeper.MockAddressPair() k.SetAddressMapping(ctx, seiAddr1, evmAddr1) seiAddr2, evmAddr2 := testkeeper.MockAddressPair() + k.SetAddressMapping(ctx, seiAddr2, evmAddr2) h := wasm.NewEVMQueryHandler(k) getEvmAddrResp := &bindings.GetEvmAddressResponse{} res, err := h.HandleGetEvmAddress(ctx, seiAddr1.String()) @@ -86,7 +95,7 @@ func TestGetAddress(t *testing.T) { res, err = h.HandleGetEvmAddress(ctx, seiAddr2.String()) require.Nil(t, err) require.Nil(t, json.Unmarshal(res, getEvmAddrResp)) - require.False(t, getEvmAddrResp.Associated) + require.True(t, getEvmAddrResp.Associated) getSeiAddrResp := &bindings.GetSeiAddressResponse{} res, err = h.HandleGetSeiAddress(ctx, evmAddr1.Hex()) require.Nil(t, err) @@ -97,5 +106,5 @@ func TestGetAddress(t *testing.T) { res, err = h.HandleGetSeiAddress(ctx, evmAddr2.Hex()) require.Nil(t, err) require.Nil(t, json.Unmarshal(res, getSeiAddrResp)) - require.False(t, getSeiAddrResp.Associated) + require.True(t, getSeiAddrResp.Associated) } diff --git a/x/evm/keeper/address.go b/x/evm/keeper/address.go index 0049ca711..99f13cc1c 100644 --- a/x/evm/keeper/address.go +++ b/x/evm/keeper/address.go @@ -45,14 +45,6 @@ func (k *Keeper) GetEVMAddressOrDefault(ctx sdk.Context, seiAddress sdk.AccAddre return common.BytesToAddress(seiAddress) } -func (k *Keeper) GetEVMAddressFromBech32OrDefault(ctx sdk.Context, seiAddress string) (common.Address, error) { - seiAddr, err := sdk.AccAddressFromBech32(seiAddress) - if err != nil { - return common.Address{}, err - } - return k.GetEVMAddressOrDefault(ctx, seiAddr), nil -} - func (k *Keeper) GetSeiAddress(ctx sdk.Context, evmAddress common.Address) (sdk.AccAddress, bool) { store := ctx.KVStore(k.storeKey) bz := store.Get(types.EVMAddressToSeiAddressKey(evmAddress)) diff --git a/x/evm/keeper/evm.go b/x/evm/keeper/evm.go index ae64cd5ba..6df3dc9ce 100644 --- a/x/evm/keeper/evm.go +++ b/x/evm/keeper/evm.go @@ -2,6 +2,7 @@ package keeper import ( "errors" + "fmt" "math" "math/big" @@ -48,6 +49,12 @@ func (k *Keeper) HandleInternalEVMDelegateCall(ctx sdk.Context, req *types.MsgIn if err != nil { return nil, err } + // delegatecall caller must be associated; otherwise any state change on EVM contract will be lost + // after they asssociate. + _, found := k.GetEVMAddress(ctx, senderAddr) + if !found { + return nil, fmt.Errorf("sender %s is not associated", req.Sender) + } ret, err := k.CallEVM(ctx, senderAddr, to, &zeroInt, req.Data) if err != nil { return nil, err diff --git a/x/evm/state/utils_test.go b/x/evm/state/utils_test.go index 286e633a8..3b01ea151 100644 --- a/x/evm/state/utils_test.go +++ b/x/evm/state/utils_test.go @@ -9,8 +9,8 @@ import ( ) func TestGetCoinbaseAddress(t *testing.T) { - coinbaseAddr := state.GetCoinbaseAddress(1) - require.Equal(t, coinbaseAddr.String(), "sei1v4mx6hmrda5kucnpwdjsqqqqqqqqqqqpz6djs7") + coinbaseAddr := state.GetCoinbaseAddress(1).String() + require.Equal(t, coinbaseAddr, "sei1v4mx6hmrda5kucnpwdjsqqqqqqqqqqqpz6djs7") } func TestSplitUseiWeiAmount(t *testing.T) { From 5caa03108624132af68c764dec1b01cb556b2f11 Mon Sep 17 00:00:00 2001 From: Steven Landers Date: Mon, 15 Apr 2024 14:46:58 -0400 Subject: [PATCH 13/17] [EVM] update sei-tendermint v0.2.41-seiv2 (#1544) update tendermint version --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index a4ce0324d..71657e956 100644 --- a/go.mod +++ b/go.mod @@ -354,7 +354,7 @@ replace ( github.com/sei-protocol/sei-db => github.com/sei-protocol/sei-db v0.0.35 // Latest goleveldb is broken, we have to stick to this version github.com/syndtr/goleveldb => github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 - github.com/tendermint/tendermint => github.com/sei-protocol/sei-tendermint v0.2.40-seiv2 + github.com/tendermint/tendermint => github.com/sei-protocol/sei-tendermint v0.2.41-seiv2 github.com/tendermint/tm-db => github.com/sei-protocol/tm-db v0.0.4 google.golang.org/grpc => google.golang.org/grpc v1.33.2 ) diff --git a/go.sum b/go.sum index 1b2828a7d..6be8c541f 100644 --- a/go.sum +++ b/go.sum @@ -1355,8 +1355,8 @@ github.com/sei-protocol/sei-iavl v0.1.9 h1:y4mVYftxLNRs6533zl7N0/Ch+CzRQc04JDfHo github.com/sei-protocol/sei-iavl v0.1.9/go.mod h1:7PfkEVT5dcoQE+s/9KWdoXJ8VVVP1QpYYPLdxlkSXFk= github.com/sei-protocol/sei-ibc-go/v3 v3.3.0 h1:/mjpTuCSEVDJ51nUDSHU92N0bRSwt49r1rmdC/lqgp8= github.com/sei-protocol/sei-ibc-go/v3 v3.3.0/go.mod h1:VwB/vWu4ysT5DN2aF78d17LYmx3omSAdq6gpKvM7XRA= -github.com/sei-protocol/sei-tendermint v0.2.40-seiv2 h1:63lbUfMSN0WpZOeR8NBEvMwKNxznKVS4UWuDzlxOOHY= -github.com/sei-protocol/sei-tendermint v0.2.40-seiv2/go.mod h1:4LSlJdhl3nf3OmohliwRNUFLOB1XWlrmSodrIP7fLh4= +github.com/sei-protocol/sei-tendermint v0.2.41-seiv2 h1:X6CGPY0zWNevTyvZafIw0dZG7Qw34N0dVmcki+hFtik= +github.com/sei-protocol/sei-tendermint v0.2.41-seiv2/go.mod h1:4LSlJdhl3nf3OmohliwRNUFLOB1XWlrmSodrIP7fLh4= github.com/sei-protocol/sei-tm-db v0.0.5 h1:3WONKdSXEqdZZeLuWYfK5hP37TJpfaUa13vAyAlvaQY= github.com/sei-protocol/sei-tm-db v0.0.5/go.mod h1:Cpa6rGyczgthq7/0pI31jys2Fw0Nfrc+/jKdP1prVqY= github.com/sei-protocol/sei-wasmd v0.1.0 h1:YCJ8SzJYMUR6hYOtgfjETFmSX1qx6cfLCmRAav2KMIs= From 7470aaec8c18bceaf76c033d15f4fcbeba6af875 Mon Sep 17 00:00:00 2001 From: Uday Patil Date: Mon, 15 Apr 2024 18:35:57 -0500 Subject: [PATCH 14/17] Add wasmd execute batch to precompile (#1529) * Add wasmd execute batch to precompile * Add some wasm hardhat it stuff * update script * Update deployment script * fix tests * update to add instantiate --- contracts/test/EVMPrecompileTester.js | 151 ++++++++- contracts/test/deploy_wasm_contract.sh | 26 ++ integration_test/evm_module/hardhat_test.yaml | 1 + precompiles/wasmd/Wasmd.sol | 8 + precompiles/wasmd/abi.json | 2 +- precompiles/wasmd/wasmd.go | 188 +++++++++-- precompiles/wasmd/wasmd_test.go | 302 +++++++++++++++++- 7 files changed, 635 insertions(+), 43 deletions(-) create mode 100644 contracts/test/deploy_wasm_contract.sh mode change 100755 => 100644 precompiles/wasmd/abi.json diff --git a/contracts/test/EVMPrecompileTester.js b/contracts/test/EVMPrecompileTester.js index 34551f898..c094334f8 100644 --- a/contracts/test/EVMPrecompileTester.js +++ b/contracts/test/EVMPrecompileTester.js @@ -19,15 +19,15 @@ describe("EVM Test", function () { console.log("ERC20 address is:"); console.log(contractAddress); await sleep(1000); - + // Create a signer [signer, signer2] = await ethers.getSigners(); owner = await signer.getAddress(); owner2 = await signer2.getAddress(); - + const contractABIPath = path.join(__dirname, '../../precompiles/common/erc20_abi.json'); const contractABI = require(contractABIPath); - + // Get a contract instance erc20 = new ethers.Contract(contractAddress, contractABI, signer); @@ -45,7 +45,7 @@ describe("EVM Test", function () { const receipt2 = await tx2.wait(); expect(receipt2.status).to.equal(1); }); - + it("Transfer function", async function() { const beforeBalance = await erc20.balanceOf(owner); const tx = await erc20.transfer(owner2, 1); @@ -77,13 +77,13 @@ describe("EVM Test", function () { expect(approveReceipt.status).to.equal(1); expect(await erc20.allowance(owner, owner2)).to.equal(100); - const erc20AsOwner2 = erc20.connect(signer2); + const erc20AsOwner2 = erc20.connect(signer2); + - // transfer from owner to owner2 const balanceBefore = await erc20.balanceOf(owner2); const transferFromTx = await erc20AsOwner2.transferFrom(owner, owner2, 100); - + // await sleep(3000); const transferFromReceipt = await transferFromTx.wait(); expect(transferFromReceipt.status).to.equal(1); @@ -91,17 +91,17 @@ describe("EVM Test", function () { const diff = balanceAfter - balanceBefore; expect(diff).to.equal(100); }); - + it("Balance of function", async function() { const balance = await erc20.balanceOf(owner); expect(balance).to.be.greaterThan(Number(0)); }); - + it("Name function", async function () { const name = await erc20.name() expect(name).to.equal('UATOM'); }); - + it("Symbol function", async function () { const symbol = await erc20.symbol() // expect symbol to be 'UATOM' @@ -117,17 +117,17 @@ describe("EVM Test", function () { before(async function() { govProposal = readDeploymentOutput('gov_proposal_output.txt'); await sleep(1000); - + // Create a proposal const [signer, _] = await ethers.getSigners(); owner = await signer.getAddress(); - + const contractABIPath = path.join(__dirname, '../../precompiles/gov/abi.json'); const contractABI = require(contractABIPath); // Get a contract instance gov = new ethers.Contract(GovPrecompileContract, contractABI, signer); }); - + it("Gov deposit", async function () { const depositAmount = ethers.parseEther('0.01'); const deposit = await gov.deposit(govProposal, { @@ -231,6 +231,122 @@ describe("EVM Test", function () { } }); }); + + describe("EVM Wasm Precompile Tester", function () { + const WasmPrecompileContract = '0x0000000000000000000000000000000000001002'; + before(async function() { + wasmContractAddress = readDeploymentOutput('wasm_contract_addr.txt'); + wasmCodeID = parseInt(readDeploymentOutput('wasm_code_id.txt')); + + const [signer, _] = await ethers.getSigners(); + owner = await signer.getAddress(); + + const contractABIPath = path.join(__dirname, '../../precompiles/wasmd/abi.json'); + const contractABI = require(contractABIPath); + // Get a contract instance + wasmd = new ethers.Contract(WasmPrecompileContract, contractABI, signer); + }); + + it("Wasm Precompile Instantiate", async function () { + encoder = new TextEncoder(); + + queryCountMsg = {get_count: {}}; + queryStr = JSON.stringify(queryCountMsg); + queryBz = encoder.encode(queryStr); + + instantiateMsg = {count: 2}; + instantiateStr = JSON.stringify(instantiateMsg); + instantiateBz = encoder.encode(instantiateStr); + + coins = []; + coinsStr = JSON.stringify(coins); + coinsBz = encoder.encode(coinsStr); + + instantiate = await wasmd.instantiate(wasmCodeID, "", instantiateBz, "counter-contract", coinsBz); + const receipt = await instantiate.wait(); + expect(receipt.status).to.equal(1); + // TODO: is there any way to get the instantiate results for contract address - or in events? + }); + + it("Wasm Precompile Execute", async function () { + expect(wasmContractAddress).to.not.be.empty; + encoder = new TextEncoder(); + + queryCountMsg = {get_count: {}}; + queryStr = JSON.stringify(queryCountMsg); + queryBz = encoder.encode(queryStr); + initialCountBz = await wasmd.query(wasmContractAddress, queryBz); + initialCount = parseHexToJSON(initialCountBz) + + incrementMsg = {increment: {}}; + incrementStr = JSON.stringify(incrementMsg); + incrementBz = encoder.encode(incrementStr); + + coins = []; + coinsStr = JSON.stringify(coins); + coinsBz = encoder.encode(coinsStr); + + execute = await wasmd.execute(wasmContractAddress, incrementBz, coinsBz); + const receipt = await execute.wait(); + expect(receipt.status).to.equal(1); + + finalCountBz = await wasmd.query(wasmContractAddress, queryBz); + finalCount = parseHexToJSON(finalCountBz) + expect(finalCount.count).to.equal(initialCount.count + 1); + }); + + it("Wasm Precompile Batch Execute", async function () { + expect(wasmContractAddress).to.not.be.empty; + encoder = new TextEncoder(); + + queryCountMsg = {get_count: {}}; + queryStr = JSON.stringify(queryCountMsg); + queryBz = encoder.encode(queryStr); + initialCountBz = await wasmd.query(wasmContractAddress, queryBz); + initialCount = parseHexToJSON(initialCountBz) + + incrementMsg = {increment: {}}; + incrementStr = JSON.stringify(incrementMsg); + incrementBz = encoder.encode(incrementStr); + + coins = []; + coinsStr = JSON.stringify(coins); + coinsBz = encoder.encode(coinsStr); + + executeBatch = [ + { + contractAddress: wasmContractAddress, + msg: incrementBz, + coins: coinsBz, + }, + { + contractAddress: wasmContractAddress, + msg: incrementBz, + coins: coinsBz, + }, + { + contractAddress: wasmContractAddress, + msg: incrementBz, + coins: coinsBz, + }, + { + contractAddress: wasmContractAddress, + msg: incrementBz, + coins: coinsBz, + }, + ]; + + executeBatch = await wasmd.execute_batch(executeBatch); + const receipt = await executeBatch.wait(); + expect(receipt.status).to.equal(1); + + finalCountBz = await wasmd.query(wasmContractAddress, queryBz); + finalCount = parseHexToJSON(finalCountBz) + expect(finalCount.count).to.equal(initialCount.count + 4); + }); + + }); + }); }); @@ -251,3 +367,12 @@ function readDeploymentOutput(fileName) { } return fileContent; } + +function parseHexToJSON(hexStr) { + // Remove the 0x prefix + hexStr = hexStr.slice(2); + // Convert to bytes + const bytes = Buffer.from(hexStr, 'hex'); + // Convert to JSON + return JSON.parse(bytes.toString()); +} \ No newline at end of file diff --git a/contracts/test/deploy_wasm_contract.sh b/contracts/test/deploy_wasm_contract.sh new file mode 100644 index 000000000..b35df1703 --- /dev/null +++ b/contracts/test/deploy_wasm_contract.sh @@ -0,0 +1,26 @@ +#!/bin/bash + +seidbin=$(which ~/go/bin/seid | tr -d '"') +keyname=$(printf "12345678\n" | $seidbin keys list --output json | jq ".[0].name" | tr -d '"') +keyaddress=$(printf "12345678\n" | $seidbin keys list --output json | jq ".[0].address" | tr -d '"') +chainid=$($seidbin status | jq ".NodeInfo.network" | tr -d '"') +seihome=$(git rev-parse --show-toplevel | tr -d '"') + +cd $seihome || exit +echo "Deploying wasm counter contract" + +echo "Storing wasm counter contract" +store_result=$(printf "12345678\n" | $seidbin tx wasm store integration_test/contracts/counter_parallel.wasm -y --from="$keyname" --chain-id="$chainid" --gas=5000000 --fees=1000000usei --broadcast-mode=block --output=json) +contract_id=$(echo "$store_result" | jq -r '.logs[].events[].attributes[] | select(.key == "code_id").value') +echo "$contract_id" > contracts/wasm_code_id.txt +echo "Instantiating wasm counter contract" +instantiate_result=$(printf "12345678\n" | $seidbin tx wasm instantiate "$contract_id" '{"count": 0}' -y --no-admin --from="$keyname" --chain-id="$chainid" --gas=5000000 --fees=1000000usei --broadcast-mode=block --label=dex --output=json) +echo $instantiate_result + +contract_addr=$(echo "$instantiate_result" |jq -r 'first(.logs[].events[].attributes[] | select(.key == "_contract_address").value)') + +echo "Deployed counter contract with address:" +echo $contract_addr + +# write the contract address to wasm_contract_addr.txt +echo "$contract_addr" > contracts/wasm_contract_addr.txt \ No newline at end of file diff --git a/integration_test/evm_module/hardhat_test.yaml b/integration_test/evm_module/hardhat_test.yaml index 344396b47..14e7c153e 100644 --- a/integration_test/evm_module/hardhat_test.yaml +++ b/integration_test/evm_module/hardhat_test.yaml @@ -11,6 +11,7 @@ - cmd: bash contracts/test/get_validator_address.sh - cmd: bash contracts/test/send_gov_proposal.sh - cmd: bash contracts/test/query_oracle_data.sh + - cmd: bash contracts/test/deploy_wasm_contract.sh verifiers: - type: eval expr: RESULT == "0x1" diff --git a/precompiles/wasmd/Wasmd.sol b/precompiles/wasmd/Wasmd.sol index f932e9a32..58d685188 100644 --- a/precompiles/wasmd/Wasmd.sol +++ b/precompiles/wasmd/Wasmd.sol @@ -23,6 +23,14 @@ interface IWasmd { bytes memory coins ) payable external returns (bytes memory response); + struct ExecuteMsg { + string contractAddress; + bytes msg; + bytes coins; + } + + function execute_batch(ExecuteMsg[] memory executeMsgs) payable external returns (bytes[] memory responses); + // Queries function query(string memory contractAddress, bytes memory req) external view returns (bytes memory response); } diff --git a/precompiles/wasmd/abi.json b/precompiles/wasmd/abi.json old mode 100755 new mode 100644 index 384d896a7..c5e5b1b3f --- a/precompiles/wasmd/abi.json +++ b/precompiles/wasmd/abi.json @@ -1 +1 @@ -[{"inputs":[{"internalType":"string","name":"contractAddress","type":"string"},{"internalType":"bytes","name":"msg","type":"bytes"},{"internalType":"bytes","name":"coins","type":"bytes"}],"name":"execute","outputs":[{"internalType":"bytes","name":"response","type":"bytes"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint64","name":"codeID","type":"uint64"},{"internalType":"string","name":"admin","type":"string"},{"internalType":"bytes","name":"msg","type":"bytes"},{"internalType":"string","name":"label","type":"string"},{"internalType":"bytes","name":"coins","type":"bytes"}],"name":"instantiate","outputs":[{"internalType":"string","name":"contractAddr","type":"string"},{"internalType":"bytes","name":"data","type":"bytes"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"string","name":"contractAddress","type":"string"},{"internalType":"bytes","name":"req","type":"bytes"}],"name":"query","outputs":[{"internalType":"bytes","name":"response","type":"bytes"}],"stateMutability":"view","type":"function"}] \ No newline at end of file +[{"inputs":[{"internalType":"string","name":"contractAddress","type":"string"},{"internalType":"bytes","name":"msg","type":"bytes"},{"internalType":"bytes","name":"coins","type":"bytes"}],"name":"execute","outputs":[{"internalType":"bytes","name":"response","type":"bytes"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"string","name":"contractAddress","type":"string"},{"internalType":"bytes","name":"msg","type":"bytes"},{"internalType":"bytes","name":"coins","type":"bytes"}],"internalType":"struct IWasmd.ExecuteMsg[]","name":"executeMsgs","type":"tuple[]"}],"name":"execute_batch","outputs":[{"internalType":"bytes[]","name":"responses","type":"bytes[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint64","name":"codeID","type":"uint64"},{"internalType":"string","name":"admin","type":"string"},{"internalType":"bytes","name":"msg","type":"bytes"},{"internalType":"string","name":"label","type":"string"},{"internalType":"bytes","name":"coins","type":"bytes"}],"name":"instantiate","outputs":[{"internalType":"string","name":"contractAddr","type":"string"},{"internalType":"bytes","name":"data","type":"bytes"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"string","name":"contractAddress","type":"string"},{"internalType":"bytes","name":"req","type":"bytes"}],"name":"query","outputs":[{"internalType":"bytes","name":"response","type":"bytes"}],"stateMutability":"view","type":"function"}] \ No newline at end of file diff --git a/precompiles/wasmd/wasmd.go b/precompiles/wasmd/wasmd.go index ad77fc3e2..06d9db253 100644 --- a/precompiles/wasmd/wasmd.go +++ b/precompiles/wasmd/wasmd.go @@ -16,12 +16,14 @@ import ( "github.com/ethereum/go-ethereum/core/vm" pcommon "github.com/sei-protocol/sei-chain/precompiles/common" "github.com/sei-protocol/sei-chain/utils" + "github.com/sei-protocol/sei-chain/x/evm/state" ) const ( - InstantiateMethod = "instantiate" - ExecuteMethod = "execute" - QueryMethod = "query" + InstantiateMethod = "instantiate" + ExecuteMethod = "execute" + ExecuteBatchMethod = "execute_batch" + QueryMethod = "query" ) const WasmdAddress = "0x0000000000000000000000000000000000001002" @@ -42,9 +44,16 @@ type Precompile struct { wasmdViewKeeper pcommon.WasmdViewKeeper address common.Address - InstantiateID []byte - ExecuteID []byte - QueryID []byte + InstantiateID []byte + ExecuteID []byte + ExecuteBatchID []byte + QueryID []byte +} + +type ExecuteMsg struct { + ContractAddress string `json:"contractAddress"` + Msg []byte `json:"msg"` + Coins []byte `json:"coins"` } func NewPrecompile(evmKeeper pcommon.EVMKeeper, wasmdKeeper pcommon.WasmdKeeper, wasmdViewKeeper pcommon.WasmdViewKeeper, bankKeeper pcommon.BankKeeper) (*Precompile, error) { @@ -69,11 +78,13 @@ func NewPrecompile(evmKeeper pcommon.EVMKeeper, wasmdKeeper pcommon.WasmdKeeper, for name, m := range newAbi.Methods { switch name { - case "instantiate": + case InstantiateMethod: p.InstantiateID = m.ID - case "execute": + case ExecuteMethod: p.ExecuteID = m.ID - case "query": + case ExecuteBatchMethod: + p.ExecuteBatchID = m.ID + case QueryMethod: p.QueryID = m.ID } } @@ -101,6 +112,8 @@ func (Precompile) IsTransaction(method string) bool { switch method { case ExecuteMethod: return true + case ExecuteBatchMethod: + return true case InstantiateMethod: return true default: @@ -129,6 +142,8 @@ func (p Precompile) RunAndCalculateGas(evm *vm.EVM, caller common.Address, calli return p.instantiate(ctx, method, caller, callingContract, args, value, readOnly) case ExecuteMethod: return p.execute(ctx, method, caller, callingContract, args, value, readOnly) + case ExecuteBatchMethod: + return p.execute_batch(ctx, method, caller, callingContract, args, value, readOnly) case QueryMethod: return p.query(ctx, method, args, value) } @@ -187,8 +202,9 @@ func (p Precompile) instantiate(ctx sdk.Context, method *abi.Method, caller comm rerr = err return } - if !coins.AmountOf(sdk.MustGetBaseDenom()).IsZero() { - rerr = errors.New("deposit of usei must be done through the `value` field") + coinsValue := coins.AmountOf(sdk.MustGetBaseDenom()).Mul(state.SdkUseiToSweiMultiplier).BigInt() + if (value == nil && coinsValue.Sign() == 1) || (value != nil && coinsValue.Cmp(value) != 0) { + rerr = errors.New("coin amount must equal value specified") return } @@ -206,14 +222,19 @@ func (p Precompile) instantiate(ctx sdk.Context, method *abi.Method, caller comm rerr = err return } - - if value != nil { - coin, err := pcommon.HandlePaymentUsei(ctx, p.evmKeeper.GetSeiAddressOrDefault(ctx, p.address), creatorAddr, value, p.bankKeeper) + useiAmt := coins.AmountOf(sdk.MustGetBaseDenom()) + if value != nil && !useiAmt.IsZero() { + useiAmtAsWei := useiAmt.Mul(state.SdkUseiToSweiMultiplier).BigInt() + coin, err := pcommon.HandlePaymentUsei(ctx, p.evmKeeper.GetSeiAddressOrDefault(ctx, p.address), creatorAddr, useiAmtAsWei, p.bankKeeper) if err != nil { rerr = err return } - coins = coins.Add(coin) + // sanity check coin amounts match + if !coin.Amount.Equal(useiAmt) { + rerr = errors.New("mismatch between coins and payment value") + return + } } addr, data, err := p.wasmdKeeper.Instantiate(ctx, codeID, creatorAddr, adminAddr, msg, label, coins) @@ -226,6 +247,125 @@ func (p Precompile) instantiate(ctx sdk.Context, method *abi.Method, caller comm return } +func (p Precompile) execute_batch(ctx sdk.Context, method *abi.Method, caller common.Address, callingContract common.Address, args []interface{}, value *big.Int, readOnly bool) (ret []byte, remainingGas uint64, rerr error) { + defer func() { + if err := recover(); err != nil { + ret = nil + remainingGas = 0 + rerr = fmt.Errorf("%s", err) + return + } + }() + if readOnly { + rerr = errors.New("cannot call execute from staticcall") + return + } + + if err := pcommon.ValidateArgsLength(args, 1); err != nil { + rerr = err + return + } + + executeMsgs := args[0].([]struct { + ContractAddress string `json:"contractAddress"` + Msg []byte `json:"msg"` + Coins []byte `json:"coins"` + }) + + responses := make([][]byte, 0, len(executeMsgs)) + + // validate coins add up to value + validateValue := big.NewInt(0) + for i := 0; i < len(executeMsgs); i++ { + executeMsg := ExecuteMsg(executeMsgs[i]) + coinsBz := executeMsg.Coins + coins := sdk.NewCoins() + if err := json.Unmarshal(coinsBz, &coins); err != nil { + rerr = err + return + } + messageAmount := coins.AmountOf(sdk.MustGetBaseDenom()).Mul(state.SdkUseiToSweiMultiplier).BigInt() + validateValue.Add(validateValue, messageAmount) + } + // if validateValue is greater than zero, then value must be provided, and they must be equal + if (value == nil && validateValue.Sign() == 1) || (value != nil && validateValue.Cmp(value) != 0) { + rerr = errors.New("sum of coin amounts must equal value specified") + return + } + for i := 0; i < len(executeMsgs); i++ { + executeMsg := ExecuteMsg(executeMsgs[i]) + + // type assertion will always succeed because it's already validated in p.Prepare call in Run() + contractAddrStr := executeMsg.ContractAddress + if caller.Cmp(callingContract) != 0 { + erc20pointer, _, erc20exists := p.evmKeeper.GetERC20CW20Pointer(ctx, contractAddrStr) + erc721pointer, _, erc721exists := p.evmKeeper.GetERC721CW721Pointer(ctx, contractAddrStr) + if (!erc20exists || erc20pointer.Cmp(callingContract) != 0) && (!erc721exists || erc721pointer.Cmp(callingContract) != 0) { + return nil, 0, fmt.Errorf("%s is not a pointer of %s", callingContract.Hex(), contractAddrStr) + } + } + + contractAddr, err := sdk.AccAddressFromBech32(contractAddrStr) + if err != nil { + rerr = err + return + } + senderAddr := p.evmKeeper.GetSeiAddressOrDefault(ctx, caller) + msg := executeMsg.Msg + coinsBz := executeMsg.Coins + coins := sdk.NewCoins() + if err := json.Unmarshal(coinsBz, &coins); err != nil { + rerr = err + return + } + useiAmt := coins.AmountOf(sdk.MustGetBaseDenom()) + if value != nil && !useiAmt.IsZero() { + // process coin amount from the value provided + useiAmtAsWei := useiAmt.Mul(state.SdkUseiToSweiMultiplier).BigInt() + coin, err := pcommon.HandlePaymentUsei(ctx, p.evmKeeper.GetSeiAddressOrDefault(ctx, p.address), senderAddr, useiAmtAsWei, p.bankKeeper) + if err != nil { + rerr = err + return + } + value.Sub(value, useiAmtAsWei) + if value.Sign() == -1 { + rerr = errors.New("insufficient value provided for payment") + return + } + // sanity check coin amounts match + if !coin.Amount.Equal(useiAmt) { + rerr = errors.New("mismatch between coins and payment value") + return + } + } + // Run basic validation, can also just expose validateLabel and validate validateWasmCode in sei-wasmd + msgExecute := wasmtypes.MsgExecuteContract{ + Sender: senderAddr.String(), + Contract: contractAddr.String(), + Msg: msg, + Funds: coins, + } + if err := msgExecute.ValidateBasic(); err != nil { + rerr = err + return + } + + res, err := p.wasmdKeeper.Execute(ctx, contractAddr, senderAddr, msg, coins) + if err != nil { + rerr = err + return + } + responses = append(responses, res) + } + if value != nil && value.Sign() != 0 { + rerr = errors.New("value remaining after execution, must match provided amounts exactly") + return + } + ret, rerr = method.Outputs.Pack(responses) + remainingGas = pcommon.GetRemainingGas(ctx, p.evmKeeper) + return +} + func (p Precompile) execute(ctx sdk.Context, method *abi.Method, caller common.Address, callingContract common.Address, args []interface{}, value *big.Int, readOnly bool) (ret []byte, remainingGas uint64, rerr error) { defer func() { if err := recover(); err != nil { @@ -271,10 +411,12 @@ func (p Precompile) execute(ctx sdk.Context, method *abi.Method, caller common.A rerr = err return } - if !coins.AmountOf(sdk.MustGetBaseDenom()).IsZero() { - rerr = errors.New("deposit of usei must be done through the `value` field") + coinsValue := coins.AmountOf(sdk.MustGetBaseDenom()).Mul(state.SdkUseiToSweiMultiplier).BigInt() + if (value == nil && coinsValue.Sign() == 1) || (value != nil && coinsValue.Cmp(value) != 0) { + rerr = errors.New("coin amount must equal value specified") return } + // Run basic validation, can also just expose validateLabel and validate validateWasmCode in sei-wasmd msgExecute := wasmtypes.MsgExecuteContract{ Sender: senderAddr.String(), @@ -288,13 +430,19 @@ func (p Precompile) execute(ctx sdk.Context, method *abi.Method, caller common.A return } - if value != nil { - coin, err := pcommon.HandlePaymentUsei(ctx, p.evmKeeper.GetSeiAddressOrDefault(ctx, p.address), senderAddr, value, p.bankKeeper) + useiAmt := coins.AmountOf(sdk.MustGetBaseDenom()) + if value != nil && !useiAmt.IsZero() { + useiAmtAsWei := useiAmt.Mul(state.SdkUseiToSweiMultiplier).BigInt() + coin, err := pcommon.HandlePaymentUsei(ctx, p.evmKeeper.GetSeiAddressOrDefault(ctx, p.address), senderAddr, useiAmtAsWei, p.bankKeeper) if err != nil { rerr = err return } - coins = coins.Add(coin) + // sanity check coin amounts match + if !coin.Amount.Equal(useiAmt) { + rerr = errors.New("mismatch between coins and payment value") + return + } } res, err := p.wasmdKeeper.Execute(ctx, contractAddr, senderAddr, msg, coins) if err != nil { diff --git a/precompiles/wasmd/wasmd_test.go b/precompiles/wasmd/wasmd_test.go index 2676802cd..9322386fc 100644 --- a/precompiles/wasmd/wasmd_test.go +++ b/precompiles/wasmd/wasmd_test.go @@ -24,6 +24,7 @@ func TestRequiredGas(t *testing.T) { require.Nil(t, err) require.Equal(t, uint64(2000), p.RequiredGas(p.ExecuteID)) require.Equal(t, uint64(2000), p.RequiredGas(p.InstantiateID)) + require.Equal(t, uint64(2000), p.RequiredGas(p.ExecuteBatchID)) require.Equal(t, uint64(1000), p.RequiredGas(p.QueryID)) require.Equal(t, uint64(3000), p.RequiredGas([]byte{15, 15, 15, 15})) // invalid method } @@ -49,7 +50,12 @@ func TestInstantiate(t *testing.T) { require.Nil(t, err) instantiateMethod, err := p.ABI.MethodById(p.InstantiateID) require.Nil(t, err) - amtsbz, err := sdk.NewCoins().MarshalJSON() + amts := sdk.NewCoins(sdk.NewCoin("usei", sdk.NewInt(1000))) + amtsbz, err := amts.MarshalJSON() + testApp.BankKeeper.MintCoins(ctx, "evm", amts) + testApp.BankKeeper.SendCoinsFromModuleToAccount(ctx, "evm", mockAddr, amts) + testApp.BankKeeper.MintCoins(ctx, "evm", amts) + testApp.BankKeeper.SendCoinsFromModuleToAccount(ctx, "evm", mockAddr, amts) require.Nil(t, err) args, err := instantiateMethod.Inputs.Pack( codeID, @@ -63,14 +69,38 @@ func TestInstantiate(t *testing.T) { evm := vm.EVM{ StateDB: statedb, } + testApp.BankKeeper.SendCoins(ctx, mockAddr, testApp.EvmKeeper.GetSeiAddressOrDefault(ctx, common.HexToAddress(wasmd.WasmdAddress)), amts) suppliedGas := uint64(1000000) - res, g, err := p.RunAndCalculateGas(&evm, mockEVMAddr, mockEVMAddr, append(p.InstantiateID, args...), suppliedGas, nil, nil, false) + res, g, err := p.RunAndCalculateGas(&evm, mockEVMAddr, mockEVMAddr, append(p.InstantiateID, args...), suppliedGas, big.NewInt(1000_000_000_000_000), nil, false) require.Nil(t, err) outputs, err := instantiateMethod.Outputs.Unpack(res) require.Nil(t, err) require.Equal(t, 2, len(outputs)) require.Equal(t, "sei1hrpna9v7vs3stzyd4z3xf00676kf78zpe2u5ksvljswn2vnjp3yslucc3n", outputs[0].(string)) require.Empty(t, outputs[1].([]byte)) + require.Equal(t, uint64(879782), g) + + amtsbz, err = sdk.NewCoins().MarshalJSON() + require.Nil(t, err) + args, err = instantiateMethod.Inputs.Pack( + codeID, + mockAddr.String(), + []byte("{}"), + "test", + amtsbz, + ) + require.Nil(t, err) + statedb = state.NewDBImpl(ctx, &testApp.EvmKeeper, true) + evm = vm.EVM{ + StateDB: statedb, + } + res, g, err = p.RunAndCalculateGas(&evm, mockEVMAddr, mockEVMAddr, append(p.InstantiateID, args...), suppliedGas, nil, nil, false) + require.Nil(t, err) + outputs, err = instantiateMethod.Outputs.Unpack(res) + require.Nil(t, err) + require.Equal(t, 2, len(outputs)) + require.Equal(t, "sei1hrpna9v7vs3stzyd4z3xf00676kf78zpe2u5ksvljswn2vnjp3yslucc3n", outputs[0].(string)) + require.Empty(t, outputs[1].([]byte)) require.Equal(t, uint64(902838), g) // non-existent code ID @@ -126,13 +156,6 @@ func TestExecute(t *testing.T) { } suppliedGas := uint64(1000000) testApp.BankKeeper.SendCoins(ctx, mockAddr, testApp.EvmKeeper.GetSeiAddressOrDefault(ctx, common.HexToAddress(wasmd.WasmdAddress)), amts) - _, _, err = p.RunAndCalculateGas(&evm, mockEVMAddr, mockEVMAddr, append(p.ExecuteID, args...), suppliedGas, nil, nil, false) - require.NotNil(t, err) // used coins instead of `value` to send usei to the contract - - amtsbz, err = sdk.NewCoins().MarshalJSON() - require.Nil(t, err) - args, err = executeMethod.Inputs.Pack(contractAddr.String(), []byte("{\"echo\":{\"message\":\"test msg\"}}"), amtsbz) - require.Nil(t, err) res, g, err := p.RunAndCalculateGas(&evm, mockEVMAddr, mockEVMAddr, append(p.ExecuteID, args...), suppliedGas, big.NewInt(1000_000_000_000_000), nil, false) require.Nil(t, err) outputs, err := executeMethod.Outputs.Unpack(res) @@ -142,6 +165,25 @@ func TestExecute(t *testing.T) { require.Equal(t, uint64(906041), g) require.Equal(t, int64(1000), testApp.BankKeeper.GetBalance(statedb.Ctx(), contractAddr, "usei").Amount.Int64()) + amtsbz, err = sdk.NewCoins().MarshalJSON() + require.Nil(t, err) + args, err = executeMethod.Inputs.Pack(contractAddr.String(), []byte("{\"echo\":{\"message\":\"test msg\"}}"), amtsbz) + require.Nil(t, err) + _, _, err = p.RunAndCalculateGas(&evm, mockEVMAddr, mockEVMAddr, append(p.ExecuteID, args...), suppliedGas, big.NewInt(1000_000_000_000_000), nil, false) + require.NotNil(t, err) // used coins instead of `value` to send usei to the contract + + args, err = executeMethod.Inputs.Pack(contractAddr.String(), []byte("{\"echo\":{\"message\":\"test msg\"}}"), amtsbz) + require.Nil(t, err) + _, _, err = p.RunAndCalculateGas(&evm, mockEVMAddr, mockEVMAddr, append(p.ExecuteID, args...), suppliedGas, big.NewInt(1000_000_000_000_000), nil, false) + require.NotNil(t, err) + + amtsbz, err = sdk.NewCoins().MarshalJSON() + require.Nil(t, err) + args, err = executeMethod.Inputs.Pack(contractAddr.String(), []byte("{\"echo\":{\"message\":\"test msg\"}}"), amtsbz) + require.Nil(t, err) + _, _, err = p.RunAndCalculateGas(&evm, mockEVMAddr, mockEVMAddr, append(p.ExecuteID, args...), suppliedGas, big.NewInt(1000_000_000_000_000), nil, false) + require.NotNil(t, err) + // allowed delegatecall contractAddrAllowed := common.BytesToAddress([]byte("contractA")) testApp.EvmKeeper.SetERC20CW20Pointer(ctx, contractAddr.String(), contractAddrAllowed) @@ -218,3 +260,245 @@ func TestQuery(t *testing.T) { require.NotNil(t, err) require.Equal(t, uint64(0), g) } + +func TestExecuteBatchOneMessage(t *testing.T) { + testApp := app.Setup(false, false) + mockAddr, mockEVMAddr := testkeeper.MockAddressPair() + ctx := testApp.GetContextForDeliverTx([]byte{}).WithBlockTime(time.Now()) + testApp.EvmKeeper.SetAddressMapping(ctx, mockAddr, mockEVMAddr) + wasmKeeper := wasmkeeper.NewDefaultPermissionKeeper(testApp.WasmKeeper) + p, err := wasmd.NewPrecompile(&testApp.EvmKeeper, wasmKeeper, testApp.WasmKeeper, testApp.BankKeeper) + require.Nil(t, err) + code, err := os.ReadFile("../../example/cosmwasm/echo/artifacts/echo.wasm") + require.Nil(t, err) + codeID, err := wasmKeeper.Create(ctx, mockAddr, code, nil) + require.Nil(t, err) + contractAddr, _, err := wasmKeeper.Instantiate(ctx, codeID, mockAddr, mockAddr, []byte("{}"), "test", sdk.NewCoins()) + require.Nil(t, err) + + amts := sdk.NewCoins(sdk.NewCoin("usei", sdk.NewInt(1000))) + testApp.BankKeeper.MintCoins(ctx, "evm", amts) + testApp.BankKeeper.SendCoinsFromModuleToAccount(ctx, "evm", mockAddr, amts) + testApp.BankKeeper.MintCoins(ctx, "evm", amts) + testApp.BankKeeper.SendCoinsFromModuleToAccount(ctx, "evm", mockAddr, amts) + amtsbz, err := amts.MarshalJSON() + require.Nil(t, err) + executeMethod, err := p.ABI.MethodById(p.ExecuteBatchID) + require.Nil(t, err) + executeMsg := wasmd.ExecuteMsg{ + ContractAddress: contractAddr.String(), + Msg: []byte("{\"echo\":{\"message\":\"test msg\"}}"), + Coins: amtsbz, + } + args, err := executeMethod.Inputs.Pack([]wasmd.ExecuteMsg{executeMsg}) + require.Nil(t, err) + statedb := state.NewDBImpl(ctx, &testApp.EvmKeeper, true) + evm := vm.EVM{ + StateDB: statedb, + } + suppliedGas := uint64(1000000) + testApp.BankKeeper.SendCoins(ctx, mockAddr, testApp.EvmKeeper.GetSeiAddressOrDefault(ctx, common.HexToAddress(wasmd.WasmdAddress)), amts) + res, g, err := p.RunAndCalculateGas(&evm, mockEVMAddr, mockEVMAddr, append(p.ExecuteBatchID, args...), suppliedGas, big.NewInt(1000_000_000_000_000), nil, false) + require.Nil(t, err) + outputs, err := executeMethod.Outputs.Unpack(res) + require.Nil(t, err) + require.Equal(t, 1, len(outputs)) + require.Equal(t, fmt.Sprintf("received test msg from %s with 1000usei", mockAddr.String()), string((outputs[0].([][]byte))[0])) + require.Equal(t, uint64(906041), g) + require.Equal(t, int64(1000), testApp.BankKeeper.GetBalance(statedb.Ctx(), contractAddr, "usei").Amount.Int64()) + + amtsbz, err = sdk.NewCoins().MarshalJSON() + require.Nil(t, err) + executeMsg = wasmd.ExecuteMsg{ + ContractAddress: contractAddr.String(), + Msg: []byte("{\"echo\":{\"message\":\"test msg\"}}"), + Coins: amtsbz, + } + args, err = executeMethod.Inputs.Pack([]wasmd.ExecuteMsg{executeMsg}) + require.Nil(t, err) + _, _, err = p.RunAndCalculateGas(&evm, mockEVMAddr, mockEVMAddr, append(p.ExecuteBatchID, args...), suppliedGas, big.NewInt(1000_000_000_000_000), nil, false) + require.NotNil(t, err) // value and amounts not equal + + // allowed delegatecall + contractAddrAllowed := common.BytesToAddress([]byte("contractA")) + testApp.EvmKeeper.SetERC20CW20Pointer(ctx, contractAddr.String(), contractAddrAllowed) + _, _, err = p.RunAndCalculateGas(&evm, mockEVMAddr, contractAddrAllowed, append(p.ExecuteBatchID, args...), suppliedGas, nil, nil, false) + require.Nil(t, err) + + // disallowed delegatecall + contractAddrDisallowed := common.BytesToAddress([]byte("contractB")) + _, _, err = p.RunAndCalculateGas(&evm, mockEVMAddr, contractAddrDisallowed, append(p.ExecuteBatchID, args...), suppliedGas, nil, nil, false) + require.NotNil(t, err) + + // bad contract address + executeMsg = wasmd.ExecuteMsg{ + ContractAddress: mockAddr.String(), + Msg: []byte("{\"echo\":{\"message\":\"test msg\"}}"), + Coins: amtsbz, + } + args, _ = executeMethod.Inputs.Pack([]wasmd.ExecuteMsg{executeMsg}) + _, g, err = p.RunAndCalculateGas(&evm, mockEVMAddr, mockEVMAddr, append(p.ExecuteBatchID, args...), suppliedGas, nil, nil, false) + require.NotNil(t, err) + require.Equal(t, uint64(0), g) + + // bad inputs + executeMsg = wasmd.ExecuteMsg{ + ContractAddress: "not bech32", + Msg: []byte("{\"echo\":{\"message\":\"test msg\"}}"), + Coins: amtsbz, + } + args, _ = executeMethod.Inputs.Pack([]wasmd.ExecuteMsg{executeMsg}) + _, g, err = p.RunAndCalculateGas(&evm, mockEVMAddr, mockEVMAddr, append(p.ExecuteBatchID, args...), suppliedGas, nil, nil, false) + require.NotNil(t, err) + require.Equal(t, uint64(0), g) + executeMsg = wasmd.ExecuteMsg{ + ContractAddress: contractAddr.String(), + Msg: []byte("{\"echo\":{\"message\":\"test msg\"}}"), + Coins: []byte("bad coins"), + } + args, _ = executeMethod.Inputs.Pack([]wasmd.ExecuteMsg{executeMsg}) + _, g, err = p.RunAndCalculateGas(&evm, mockEVMAddr, mockEVMAddr, append(p.ExecuteBatchID, args...), suppliedGas, nil, nil, false) + require.NotNil(t, err) + require.Equal(t, uint64(0), g) +} + +func TestExecuteBatchMultipleMessages(t *testing.T) { + testApp := app.Setup(false, false) + mockAddr, mockEVMAddr := testkeeper.MockAddressPair() + ctx := testApp.GetContextForDeliverTx([]byte{}).WithBlockTime(time.Now()) + testApp.EvmKeeper.SetAddressMapping(ctx, mockAddr, mockEVMAddr) + wasmKeeper := wasmkeeper.NewDefaultPermissionKeeper(testApp.WasmKeeper) + p, err := wasmd.NewPrecompile(&testApp.EvmKeeper, wasmKeeper, testApp.WasmKeeper, testApp.BankKeeper) + require.Nil(t, err) + code, err := os.ReadFile("../../example/cosmwasm/echo/artifacts/echo.wasm") + require.Nil(t, err) + codeID, err := wasmKeeper.Create(ctx, mockAddr, code, nil) + require.Nil(t, err) + contractAddr, _, err := wasmKeeper.Instantiate(ctx, codeID, mockAddr, mockAddr, []byte("{}"), "test", sdk.NewCoins()) + require.Nil(t, err) + + amts := sdk.NewCoins(sdk.NewCoin("usei", sdk.NewInt(1000))) + largeAmts := sdk.NewCoins(sdk.NewCoin("usei", sdk.NewInt(3000))) + testApp.BankKeeper.MintCoins(ctx, "evm", sdk.NewCoins(sdk.NewCoin("usei", sdk.NewInt(13000)))) + testApp.BankKeeper.SendCoinsFromModuleToAccount(ctx, "evm", mockAddr, sdk.NewCoins(sdk.NewCoin("usei", sdk.NewInt(13000)))) + amtsbz, err := amts.MarshalJSON() + require.Nil(t, err) + executeMethod, err := p.ABI.MethodById(p.ExecuteBatchID) + require.Nil(t, err) + executeMsgWithCoinsAmt := wasmd.ExecuteMsg{ + ContractAddress: contractAddr.String(), + Msg: []byte("{\"echo\":{\"message\":\"test msg\"}}"), + Coins: amtsbz, + } + + statedb := state.NewDBImpl(ctx, &testApp.EvmKeeper, true) + evm := vm.EVM{ + StateDB: statedb, + } + suppliedGas := uint64(1000000) + err = testApp.BankKeeper.SendCoins(ctx, mockAddr, testApp.EvmKeeper.GetSeiAddressOrDefault(ctx, common.HexToAddress(wasmd.WasmdAddress)), largeAmts) + require.Nil(t, err) + args, err := executeMethod.Inputs.Pack([]wasmd.ExecuteMsg{executeMsgWithCoinsAmt, executeMsgWithCoinsAmt, executeMsgWithCoinsAmt}) + require.Nil(t, err) + res, g, err := p.RunAndCalculateGas(&evm, mockEVMAddr, mockEVMAddr, append(p.ExecuteBatchID, args...), suppliedGas, big.NewInt(3000_000_000_000_000), nil, false) + require.Nil(t, err) + outputs, err := executeMethod.Outputs.Unpack(res) + require.Nil(t, err) + require.Equal(t, 1, len(outputs)) + parsedOutputs := outputs[0].([][]byte) + require.Equal(t, fmt.Sprintf("received test msg from %s with 1000usei", mockAddr.String()), string(parsedOutputs[0])) + require.Equal(t, fmt.Sprintf("received test msg from %s with 1000usei", mockAddr.String()), string(parsedOutputs[1])) + require.Equal(t, fmt.Sprintf("received test msg from %s with 1000usei", mockAddr.String()), string(parsedOutputs[2])) + require.Equal(t, uint64(725379), g) + require.Equal(t, int64(3000), testApp.BankKeeper.GetBalance(statedb.Ctx(), contractAddr, "usei").Amount.Int64()) + + amtsbz2, err := sdk.NewCoins().MarshalJSON() + require.Nil(t, err) + executeMsgWithNoCoins := wasmd.ExecuteMsg{ + ContractAddress: contractAddr.String(), + Msg: []byte("{\"echo\":{\"message\":\"test msg\"}}"), + Coins: amtsbz2, + } + statedb = state.NewDBImpl(ctx, &testApp.EvmKeeper, true) + evm = vm.EVM{ + StateDB: statedb, + } + err = testApp.BankKeeper.SendCoins(ctx, mockAddr, testApp.EvmKeeper.GetSeiAddressOrDefault(ctx, common.HexToAddress(wasmd.WasmdAddress)), amts) + require.Nil(t, err) + args, err = executeMethod.Inputs.Pack([]wasmd.ExecuteMsg{executeMsgWithNoCoins, executeMsgWithCoinsAmt, executeMsgWithNoCoins}) + require.Nil(t, err) + res, g, err = p.RunAndCalculateGas(&evm, mockEVMAddr, mockEVMAddr, append(p.ExecuteBatchID, args...), suppliedGas, big.NewInt(1000_000_000_000_000), nil, false) + require.Nil(t, err) + outputs, err = executeMethod.Outputs.Unpack(res) + require.Nil(t, err) + require.Equal(t, 1, len(outputs)) + parsedOutputs = outputs[0].([][]byte) + require.Equal(t, fmt.Sprintf("received test msg from %s with", mockAddr.String()), string(parsedOutputs[0])) + require.Equal(t, fmt.Sprintf("received test msg from %s with 1000usei", mockAddr.String()), string(parsedOutputs[1])) + require.Equal(t, fmt.Sprintf("received test msg from %s with", mockAddr.String()), string(parsedOutputs[2])) + require.Equal(t, uint64(773900), g) + require.Equal(t, int64(1000), testApp.BankKeeper.GetBalance(statedb.Ctx(), contractAddr, "usei").Amount.Int64()) + + // allowed delegatecall + args, err = executeMethod.Inputs.Pack([]wasmd.ExecuteMsg{executeMsgWithNoCoins, executeMsgWithNoCoins}) + require.Nil(t, err) + contractAddrAllowed := common.BytesToAddress([]byte("contractA")) + testApp.EvmKeeper.SetERC20CW20Pointer(ctx, contractAddr.String(), contractAddrAllowed) + _, _, err = p.RunAndCalculateGas(&evm, mockEVMAddr, contractAddrAllowed, append(p.ExecuteBatchID, args...), suppliedGas, nil, nil, false) + require.Nil(t, err) + + // disallowed delegatecall + contractAddrDisallowed := common.BytesToAddress([]byte("contractB")) + _, _, err = p.RunAndCalculateGas(&evm, mockEVMAddr, contractAddrDisallowed, append(p.ExecuteBatchID, args...), suppliedGas, nil, nil, false) + require.NotNil(t, err) + + // bad contract address + executeMsgBadContract := wasmd.ExecuteMsg{ + ContractAddress: mockAddr.String(), + Msg: []byte("{\"echo\":{\"message\":\"test msg\"}}"), + Coins: amtsbz, + } + statedb = state.NewDBImpl(ctx, &testApp.EvmKeeper, true) + evm = vm.EVM{ + StateDB: statedb, + } + err = testApp.BankKeeper.SendCoins(ctx, mockAddr, testApp.EvmKeeper.GetSeiAddressOrDefault(ctx, common.HexToAddress(wasmd.WasmdAddress)), largeAmts) + require.Nil(t, err) + args, err = executeMethod.Inputs.Pack([]wasmd.ExecuteMsg{executeMsgWithCoinsAmt, executeMsgBadContract, executeMsgWithCoinsAmt}) + require.Nil(t, err) + _, g, err = p.RunAndCalculateGas(&evm, mockEVMAddr, mockEVMAddr, append(p.ExecuteBatchID, args...), suppliedGas, big.NewInt(3000_000_000_000_000), nil, false) + require.NotNil(t, err) + require.Equal(t, uint64(0), g) + + // bad inputs + executeMsgBadInputs := wasmd.ExecuteMsg{ + ContractAddress: "not bech32", + Msg: []byte("{\"echo\":{\"message\":\"test msg\"}}"), + Coins: amtsbz, + } + statedb = state.NewDBImpl(ctx, &testApp.EvmKeeper, true) + evm = vm.EVM{ + StateDB: statedb, + } + err = testApp.BankKeeper.SendCoins(ctx, mockAddr, testApp.EvmKeeper.GetSeiAddressOrDefault(ctx, common.HexToAddress(wasmd.WasmdAddress)), largeAmts) + require.Nil(t, err) + args, _ = executeMethod.Inputs.Pack([]wasmd.ExecuteMsg{executeMsgWithCoinsAmt, executeMsgBadInputs, executeMsgWithCoinsAmt}) + _, g, err = p.RunAndCalculateGas(&evm, mockEVMAddr, mockEVMAddr, append(p.ExecuteBatchID, args...), suppliedGas, big.NewInt(3000_000_000_000_000), nil, false) + require.NotNil(t, err) + require.Equal(t, uint64(0), g) + executeMsgBadInputCoins := wasmd.ExecuteMsg{ + ContractAddress: contractAddr.String(), + Msg: []byte("{\"echo\":{\"message\":\"test msg\"}}"), + Coins: []byte("bad coins"), + } + statedb = state.NewDBImpl(ctx, &testApp.EvmKeeper, true) + evm = vm.EVM{ + StateDB: statedb, + } + err = testApp.BankKeeper.SendCoins(ctx, mockAddr, testApp.EvmKeeper.GetSeiAddressOrDefault(ctx, common.HexToAddress(wasmd.WasmdAddress)), largeAmts) + require.Nil(t, err) + args, _ = executeMethod.Inputs.Pack([]wasmd.ExecuteMsg{executeMsgWithCoinsAmt, executeMsgBadInputCoins, executeMsgWithCoinsAmt}) + _, g, err = p.RunAndCalculateGas(&evm, mockEVMAddr, mockEVMAddr, append(p.ExecuteBatchID, args...), suppliedGas, big.NewInt(3000_000_000_000_000), nil, false) + require.NotNil(t, err) + require.Equal(t, uint64(0), g) +} From fbe9c80f411dcfb5869a637d52bf979c942d3e91 Mon Sep 17 00:00:00 2001 From: codchen Date: Tue, 16 Apr 2024 12:16:01 +0800 Subject: [PATCH 15/17] [EVM] charge fees in ante handler (#1543) --- app/ante_test.go | 2 +- cmd/seid/cmd/blocktest.go | 3 ++ go.mod | 2 +- go.sum | 4 +-- precompiles/bank/bank_test.go | 29 +++++++++++---- x/evm/ante/fee.go | 38 ++++++++++++++++---- x/evm/ante/fee_test.go | 63 ++------------------------------- x/evm/derived/derived.go | 1 + x/evm/keeper/evm.go | 2 +- x/evm/keeper/keeper.go | 1 + x/evm/keeper/msg_server.go | 15 ++++---- x/evm/keeper/msg_server_test.go | 52 ++++++++++++++++++++++++++- x/evm/state/statedb.go | 7 ++++ x/evm/types/config.go | 4 ++- 14 files changed, 136 insertions(+), 87 deletions(-) diff --git a/app/ante_test.go b/app/ante_test.go index 91b6bc932..608b97dee 100644 --- a/app/ante_test.go +++ b/app/ante_test.go @@ -262,5 +262,5 @@ func TestEvmAnteErrorHandler(t *testing.T) { }}) deferredInfo := testkeeper.EVMTestApp.EvmKeeper.GetEVMTxDeferredInfo(ctx) require.Equal(t, 1, len(deferredInfo)) - require.Equal(t, "incorrect account sequence", deferredInfo[0].Error) + require.Contains(t, deferredInfo[0].Error, "nonce too high") } diff --git a/cmd/seid/cmd/blocktest.go b/cmd/seid/cmd/blocktest.go index 10820a096..177eef0e6 100644 --- a/cmd/seid/cmd/blocktest.go +++ b/cmd/seid/cmd/blocktest.go @@ -18,6 +18,7 @@ import ( aclkeeper "github.com/cosmos/cosmos-sdk/x/accesscontrol/keeper" ethtests "github.com/ethereum/go-ethereum/tests" "github.com/sei-protocol/sei-chain/app" + evmtypes "github.com/sei-protocol/sei-chain/x/evm/types" "github.com/tendermint/tendermint/libs/log" //nolint:gosec,G108 @@ -57,6 +58,8 @@ func BlocktestCmd(defaultNodeHome string) *cobra.Command { cache := store.NewCommitKVStoreCacheManager() wasmGasRegisterConfig := wasmkeeper.DefaultGasRegisterConfig() wasmGasRegisterConfig.GasMultiplier = 21_000_000 + // turn on Cancun for block test + evmtypes.CancunTime = 0 a := app.New( logger, db, diff --git a/go.mod b/go.mod index 71657e956..f0057b3af 100644 --- a/go.mod +++ b/go.mod @@ -349,7 +349,7 @@ replace ( github.com/cosmos/cosmos-sdk => github.com/sei-protocol/sei-cosmos v0.2.80-seiv2 github.com/cosmos/iavl => github.com/sei-protocol/sei-iavl v0.1.9 github.com/cosmos/ibc-go/v3 => github.com/sei-protocol/sei-ibc-go/v3 v3.3.0 - github.com/ethereum/go-ethereum => github.com/sei-protocol/go-ethereum v1.13.5-sei-13 + github.com/ethereum/go-ethereum => github.com/sei-protocol/go-ethereum v1.13.5-sei-15 github.com/gogo/protobuf => github.com/regen-network/protobuf v1.3.3-alpha.regen.1 github.com/sei-protocol/sei-db => github.com/sei-protocol/sei-db v0.0.35 // Latest goleveldb is broken, we have to stick to this version diff --git a/go.sum b/go.sum index 6be8c541f..ececc606f 100644 --- a/go.sum +++ b/go.sum @@ -1343,8 +1343,8 @@ github.com/seccomp/libseccomp-golang v0.9.2-0.20220502022130-f33da4d89646/go.mod github.com/securego/gosec/v2 v2.11.0 h1:+PDkpzR41OI2jrw1q6AdXZCbsNGNGT7pQjal0H0cArI= github.com/securego/gosec/v2 v2.11.0/go.mod h1:SX8bptShuG8reGC0XS09+a4H2BoWSJi+fscA+Pulbpo= github.com/segmentio/fasthash v1.0.3/go.mod h1:waKX8l2N8yckOgmSsXJi7x1ZfdKZ4x7KRMzBtS3oedY= -github.com/sei-protocol/go-ethereum v1.13.5-sei-13 h1:ied1MMoqJyTEPvT7AtJeVTn3bEuwksInfvyXxp2siLw= -github.com/sei-protocol/go-ethereum v1.13.5-sei-13/go.mod h1:kcRZmuzRn1lVejiFNTz4l4W7imnpq1bDAnuKS/RyhbQ= +github.com/sei-protocol/go-ethereum v1.13.5-sei-15 h1:VSFQrbWnSDCPCQzsYDW3k07EP3yPZb+4xAcED9kSKpg= +github.com/sei-protocol/go-ethereum v1.13.5-sei-15/go.mod h1:kcRZmuzRn1lVejiFNTz4l4W7imnpq1bDAnuKS/RyhbQ= github.com/sei-protocol/goutils v0.0.2 h1:Bfa7Sv+4CVLNM20QcpvGb81B8C5HkQC/kW1CQpIbXDA= github.com/sei-protocol/goutils v0.0.2/go.mod h1:iYE2DuJfEnM+APPehr2gOUXfuLuPsVxorcDO+Tzq9q8= github.com/sei-protocol/sei-cosmos v0.2.80-seiv2 h1:stu0hTZmQWvewzr/y40iZrKsKHFuCXFKNEJGsgivvL4= diff --git a/precompiles/bank/bank_test.go b/precompiles/bank/bank_test.go index 6e2e4b328..d8ad3e986 100644 --- a/precompiles/bank/bank_test.go +++ b/precompiles/bank/bank_test.go @@ -7,7 +7,9 @@ import ( "strings" "testing" + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/tx/signing" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" "github.com/ethereum/go-ethereum/common" ethtypes "github.com/ethereum/go-ethereum/core/types" @@ -24,6 +26,17 @@ import ( tmtypes "github.com/tendermint/tendermint/proto/tendermint/types" ) +type mockTx struct { + msgs []sdk.Msg + signers []sdk.AccAddress +} + +func (tx mockTx) GetMsgs() []sdk.Msg { return tx.msgs } +func (tx mockTx) ValidateBasic() error { return nil } +func (tx mockTx) GetSigners() []sdk.AccAddress { return tx.signers } +func (tx mockTx) GetPubKeys() ([]cryptotypes.PubKey, error) { return nil, nil } +func (tx mockTx) GetSignaturesV2() ([]signing.SignatureV2, error) { return nil, nil } + func TestRun(t *testing.T) { testApp := testkeeper.EVMTestApp ctx := testApp.NewContext(false, tmtypes.Header{}).WithBlockHeight(2) @@ -93,8 +106,8 @@ func TestRun(t *testing.T) { key, _ := crypto.HexToECDSA(testPrivHex) addr := common.HexToAddress(bank.BankAddress) txData := ethtypes.LegacyTx{ - GasPrice: big.NewInt(100000), - Gas: 20000000, + GasPrice: big.NewInt(1000000000000), + Gas: 200000, To: &addr, Value: big.NewInt(10_000_000_000_100), Data: argsNative, @@ -116,6 +129,10 @@ func TestRun(t *testing.T) { msgServer := keeper.NewMsgServerImpl(k) ante.Preprocess(ctx, req) ctx = ctx.WithEventManager(sdk.NewEventManager()) + ctx, err = ante.NewEVMFeeCheckDecorator(k).AnteHandle(ctx, mockTx{msgs: []sdk.Msg{req}}, false, func(sdk.Context, sdk.Tx, bool) (sdk.Context, error) { + return ctx, nil + }) + require.Nil(t, err) res, err := msgServer.EVMTransaction(sdk.WrapSDKContext(ctx), req) require.Nil(t, err) require.Empty(t, res.VmError) @@ -132,7 +149,7 @@ func TestRun(t *testing.T) { var expectedEvts sdk.Events = []sdk.Event{ // gas is sent from sender - banktypes.NewCoinSpentEvent(senderAddr, sdk.NewCoins(sdk.NewCoin("usei", sdk.NewInt(2)))), + banktypes.NewCoinSpentEvent(senderAddr, sdk.NewCoins(sdk.NewCoin("usei", sdk.NewInt(200000)))), // sender sends coin to the receiver banktypes.NewCoinSpentEvent(senderAddr, sdk.NewCoins(sdk.NewCoin("usei", sdk.NewInt(10)))), banktypes.NewCoinReceivedEvent(seiAddr, sdk.NewCoins(sdk.NewCoin("usei", sdk.NewInt(10)))), @@ -147,9 +164,9 @@ func TestRun(t *testing.T) { sdk.NewAttribute(banktypes.AttributeKeySender, senderAddr.String()), ), // gas refund to the sender - banktypes.NewCoinReceivedEvent(senderAddr, sdk.NewCoins(sdk.NewCoin("usei", sdk.NewInt(1)))), + banktypes.NewCoinReceivedEvent(senderAddr, sdk.NewCoins(sdk.NewCoin("usei", sdk.NewInt(172056)))), // tip is paid to the validator - banktypes.NewCoinReceivedEvent(sdk.MustAccAddressFromBech32("sei1v4mx6hmrda5kucnpwdjsqqqqqqqqqqqqlve8dv"), sdk.NewCoins(sdk.NewCoin("usei", sdk.NewInt(0)))), + banktypes.NewCoinReceivedEvent(sdk.MustAccAddressFromBech32("sei1v4mx6hmrda5kucnpwdjsqqqqqqqqqqqqlve8dv"), sdk.NewCoins(sdk.NewCoin("usei", sdk.NewInt(27944)))), } require.EqualValues(t, expectedEvts.ToABCIEvents(), evts) @@ -189,7 +206,7 @@ func TestRun(t *testing.T) { Denom: "ufoo", }, bank.CoinBalance(parsedBalances[0])) require.Equal(t, bank.CoinBalance{ - Amount: big.NewInt(9999989), + Amount: big.NewInt(9972045), Denom: "usei", }, bank.CoinBalance(parsedBalances[1])) diff --git a/x/evm/ante/fee.go b/x/evm/ante/fee.go index a3210b3f2..1e64bd920 100644 --- a/x/evm/ante/fee.go +++ b/x/evm/ante/fee.go @@ -6,6 +6,8 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/ethereum/go-ethereum/consensus/misc/eip4844" + "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/core/vm" "github.com/sei-protocol/sei-chain/app/antedecorators" "github.com/sei-protocol/sei-chain/utils" "github.com/sei-protocol/sei-chain/x/evm/derived" @@ -55,13 +57,37 @@ func (fc EVMFeeCheckDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate b } } - // fee + value - anteCharge := txData.Cost() // this would include blob fee if it's a blob tx - - senderEVMAddr := evmtypes.MustGetEVMTransactionMessage(tx).Derived.SenderEVMAddr // check if the sender has enough balance to cover fees - if state.NewDBImpl(ctx, fc.evmKeeper, true).GetBalance(senderEVMAddr).Cmp(anteCharge) < 0 { - return ctx, sdkerrors.ErrInsufficientFunds + etx, _ := msg.AsTransaction() + emsg := fc.evmKeeper.GetEVMMessage(ctx, etx, msg.Derived.SenderEVMAddr) + stateDB := state.NewDBImpl(ctx, fc.evmKeeper, false) + gp := fc.evmKeeper.GetGasPool() + blockCtx, err := fc.evmKeeper.GetVMBlockContext(ctx, gp) + if err != nil { + return ctx, err + } + cfg := evmtypes.DefaultChainConfig().EthereumConfig(fc.evmKeeper.ChainID(ctx)) + txCtx := core.NewEVMTxContext(emsg) + evmInstance := vm.NewEVM(*blockCtx, txCtx, stateDB, cfg, vm.Config{}) + stateDB.SetEVM(evmInstance) + st := core.NewStateTransition(evmInstance, emsg, &gp, true) + // run stateless checks before charging gas (mimicking Geth behavior) + if !ctx.IsCheckTx() && !ctx.IsReCheckTx() { + // we don't want to run nonce check here for CheckTx because we have special + // logic for pending nonce during CheckTx in sig.go + if err := st.StatelessChecks(); err != nil { + return ctx, err + } + } + if err := st.BuyGas(); err != nil { + return ctx, sdkerrors.Wrap(sdkerrors.ErrInsufficientFunds, err.Error()) + } + if !ctx.IsCheckTx() && !ctx.IsReCheckTx() { + surplus, err := stateDB.Finalize() + if err != nil { + return ctx, err + } + msg.Derived.AnteSurplus = surplus } // calculate the priority by dividing the total fee with the native gas limit (i.e. the effective native gas price) diff --git a/x/evm/ante/fee_test.go b/x/evm/ante/fee_test.go index 4fcb3572b..8b47c980e 100644 --- a/x/evm/ante/fee_test.go +++ b/x/evm/ante/fee_test.go @@ -10,7 +10,6 @@ import ( "github.com/ethereum/go-ethereum/common" ethtypes "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" - "github.com/holiman/uint256" "github.com/sei-protocol/sei-chain/app/antedecorators" testkeeper "github.com/sei-protocol/sei-chain/testutil/keeper" "github.com/sei-protocol/sei-chain/x/evm/ante" @@ -20,7 +19,7 @@ import ( "github.com/stretchr/testify/require" ) -func TestEVMFeeCheckDecoratorCancun(t *testing.T) { +func TestEVMFeeCheckDecorator(t *testing.T) { k, ctx := testkeeper.MockEVMKeeper() handler := ante.NewEVMFeeCheckDecorator(k) privKey := testkeeper.MockPrivateKey() @@ -30,7 +29,7 @@ func TestEVMFeeCheckDecoratorCancun(t *testing.T) { copy(to[:], []byte("0x1234567890abcdef1234567890abcdef12345678")) chainID := k.ChainID(ctx) txData := ethtypes.DynamicFeeTx{ - Nonce: 1, + Nonce: 0, GasFeeCap: big.NewInt(10000000000000), Gas: 1000, To: to, @@ -95,64 +94,6 @@ func TestEVMFeeCheckDecoratorCancun(t *testing.T) { }) require.Nil(t, err) - // should fail because blob gas fee cap is too low - blobTxData := ethtypes.BlobTx{ - Nonce: 1, - GasFeeCap: uint256.MustFromBig(txData.GasFeeCap), - Gas: 1000, - To: *to, - Value: uint256.NewInt(1000000000000000), - Data: []byte("abc"), - BlobHashes: []common.Hash{{}}, - ChainID: uint256.MustFromBig(chainID), - } - tx, err = ethtypes.SignTx(ethtypes.NewTx(&blobTxData), signer, key) - require.Nil(t, err) - typedBlobTx, err := ethtx.NewBlobTx(tx) - require.Nil(t, err) - msg, err = types.NewMsgEVMTransaction(typedBlobTx) - require.Nil(t, err) - ctx, err = preprocessor.AnteHandle(ctx, mockTx{msgs: []sdk.Msg{msg}}, false, func(ctx sdk.Context, _ sdk.Tx, _ bool) (sdk.Context, error) { - return ctx, nil - }) - require.Nil(t, err) - _, err = handler.AnteHandle(ctx, mockTx{msgs: []sdk.Msg{msg}}, false, func(ctx sdk.Context, _ sdk.Tx, _ bool) (sdk.Context, error) { - return ctx, nil - }) - require.NotNil(t, err) - - // should fail because insufficient balance due to additional blob cost - blobTxData.BlobFeeCap = uint256.NewInt(1000000000000) - tx, err = ethtypes.SignTx(ethtypes.NewTx(&blobTxData), signer, key) - require.Nil(t, err) - typedBlobTx, err = ethtx.NewBlobTx(tx) - require.Nil(t, err) - msg, err = types.NewMsgEVMTransaction(typedBlobTx) - require.Nil(t, err) - ctx, err = preprocessor.AnteHandle(ctx, mockTx{msgs: []sdk.Msg{msg}}, false, func(ctx sdk.Context, _ sdk.Tx, _ bool) (sdk.Context, error) { - return ctx, nil - }) - require.Nil(t, err) - _, err = handler.AnteHandle(ctx, mockTx{msgs: []sdk.Msg{msg}}, false, func(ctx sdk.Context, _ sdk.Tx, _ bool) (sdk.Context, error) { - return ctx, nil - }) - require.NotNil(t, err) - - // should succeed - amt = new(big.Int).Mul(typedBlobTx.GetBlobFeeCap(), new(big.Int).SetUint64(typedBlobTx.BlobGas())) - coinsAmt = sdk.NewCoins(sdk.NewCoin(k.GetBaseDenom(ctx), sdk.NewIntFromBigInt(amt))) - k.BankKeeper().MintCoins(ctx, types.ModuleName, coinsAmt) - k.BankKeeper().SendCoinsFromModuleToAccount(ctx, types.ModuleName, seiAddr, coinsAmt) - - ctx, err = preprocessor.AnteHandle(ctx, mockTx{msgs: []sdk.Msg{msg}}, false, func(ctx sdk.Context, _ sdk.Tx, _ bool) (sdk.Context, error) { - return ctx, nil - }) - require.Nil(t, err) - _, err = handler.AnteHandle(ctx, mockTx{msgs: []sdk.Msg{msg}}, false, func(ctx sdk.Context, _ sdk.Tx, _ bool) (sdk.Context, error) { - return ctx, nil - }) - require.Nil(t, err) - // should fail because of minimum fee txData.GasFeeCap = big.NewInt(0) tx, err = ethtypes.SignTx(ethtypes.NewTx(&txData), signer, key) diff --git a/x/evm/derived/derived.go b/x/evm/derived/derived.go index 810df0b27..a97d64b8a 100644 --- a/x/evm/derived/derived.go +++ b/x/evm/derived/derived.go @@ -19,6 +19,7 @@ type Derived struct { PubKey *secp256k1.PubKey IsAssociate bool Version SignerVersion + AnteSurplus sdk.Int } // Derived should never come from deserialization or be transmitted after serialization, diff --git a/x/evm/keeper/evm.go b/x/evm/keeper/evm.go index 6df3dc9ce..3bce9a770 100644 --- a/x/evm/keeper/evm.go +++ b/x/evm/keeper/evm.go @@ -131,7 +131,7 @@ func (k *Keeper) getOrCreateEVM(ctx sdk.Context, from sdk.AccAddress) (*vm.EVM, } executionCtx := ctx.WithGasMeter(sdk.NewInfiniteGasMeter()) stateDB := state.NewDBImpl(executionCtx, k, false) - executionCtx, gp := k.getGasPool(executionCtx) + gp := k.GetGasPool() blockCtx, err := k.GetVMBlockContext(executionCtx, gp) if err != nil { return nil, nil, err diff --git a/x/evm/keeper/keeper.go b/x/evm/keeper/keeper.go index 92f98af7c..209732843 100644 --- a/x/evm/keeper/keeper.go +++ b/x/evm/keeper/keeper.go @@ -200,6 +200,7 @@ func (k *Keeper) GetVMBlockContext(ctx sdk.Context, gp core.GasPool) (*vm.BlockC Time: uint64(ctx.BlockHeader().Time.Unix()), Difficulty: utils.Big0, // only needed for PoW BaseFee: k.GetBaseFeePerGas(ctx).TruncateInt().BigInt(), // feemarket not enabled + BlobBaseFee: utils.Big0, // Cancun not enabled Random: &rh, }, nil } diff --git a/x/evm/keeper/msg_server.go b/x/evm/keeper/msg_server.go index d589273ac..78ea4ab86 100644 --- a/x/evm/keeper/msg_server.go +++ b/x/evm/keeper/msg_server.go @@ -58,9 +58,10 @@ func (server msgServer) EVMTransaction(goCtx context.Context, msg *types.MsgEVMT ctx = ctx.WithGasMeter(sdk.NewInfiniteGasMeter()) stateDB := state.NewDBImpl(ctx, &server, false) + stateDB.AddSurplus(msg.Derived.AnteSurplus) tx, _ := msg.AsTransaction() - ctx, gp := server.getGasPool(ctx) - emsg := server.getEVMMessage(ctx, tx, msg.Derived.SenderEVMAddr) + emsg := server.GetEVMMessage(ctx, tx, msg.Derived.SenderEVMAddr) + gp := server.GetGasPool() defer func() { if pe := recover(); pe != nil { @@ -162,11 +163,11 @@ func (server msgServer) EVMTransaction(goCtx context.Context, msg *types.MsgEVMT return } -func (k *Keeper) getGasPool(ctx sdk.Context) (sdk.Context, core.GasPool) { - return ctx, math.MaxUint64 +func (k *Keeper) GetGasPool() core.GasPool { + return math.MaxUint64 } -func (server msgServer) getEVMMessage(ctx sdk.Context, tx *ethtypes.Transaction, sender common.Address) *core.Message { +func (k *Keeper) GetEVMMessage(ctx sdk.Context, tx *ethtypes.Transaction, sender common.Address) *core.Message { msg := &core.Message{ Nonce: tx.Nonce(), GasLimit: tx.Gas(), @@ -183,7 +184,7 @@ func (server msgServer) getEVMMessage(ctx sdk.Context, tx *ethtypes.Transaction, From: sender, } // If baseFee provided, set gasPrice to effectiveGasPrice. - baseFee := server.GetBaseFee(ctx) + baseFee := k.GetBaseFee(ctx) if baseFee != nil { msg.GasPrice = cmath.BigMin(msg.GasPrice.Add(msg.GasTipCap, baseFee), msg.GasFeeCap) } @@ -199,7 +200,7 @@ func (server msgServer) applyEVMMessage(ctx sdk.Context, msg *core.Message, stat txCtx := core.NewEVMTxContext(msg) evmInstance := vm.NewEVM(*blockCtx, txCtx, stateDB, cfg, vm.Config{}) stateDB.SetEVM(evmInstance) - st := core.NewStateTransition(evmInstance, msg, &gp) + st := core.NewStateTransition(evmInstance, msg, &gp, true) // fee already charged in ante handler res, err := st.TransitionDb() return res, err } diff --git a/x/evm/keeper/msg_server_test.go b/x/evm/keeper/msg_server_test.go index 6dfc66605..5d1fc24ea 100644 --- a/x/evm/keeper/msg_server_test.go +++ b/x/evm/keeper/msg_server_test.go @@ -7,7 +7,9 @@ import ( "os" "testing" + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/tx/signing" "github.com/ethereum/go-ethereum/common" ethtypes "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" @@ -25,6 +27,17 @@ import ( "github.com/stretchr/testify/require" ) +type mockTx struct { + msgs []sdk.Msg + signers []sdk.AccAddress +} + +func (tx mockTx) GetMsgs() []sdk.Msg { return tx.msgs } +func (tx mockTx) ValidateBasic() error { return nil } +func (tx mockTx) GetSigners() []sdk.AccAddress { return tx.signers } +func (tx mockTx) GetPubKeys() ([]cryptotypes.PubKey, error) { return nil, nil } +func (tx mockTx) GetSignaturesV2() ([]signing.SignatureV2, error) { return nil, nil } + func TestEVMTransaction(t *testing.T) { k, ctx := testkeeper.MockEVMKeeper() code, err := os.ReadFile("../../../example/contracts/simplestorage/SimpleStorage.bin") @@ -63,6 +76,10 @@ func TestEVMTransaction(t *testing.T) { // Deploy Simple Storage contract ante.Preprocess(ctx, req) + ctx, err = ante.NewEVMFeeCheckDecorator(k).AnteHandle(ctx, mockTx{msgs: []sdk.Msg{req}}, false, func(sdk.Context, sdk.Tx, bool) (sdk.Context, error) { + return ctx, nil + }) + require.Nil(t, err) res, err := msgServer.EVMTransaction(sdk.WrapSDKContext(ctx), req) require.Nil(t, err) require.LessOrEqual(t, res.GasUsed, uint64(200000)) @@ -97,6 +114,10 @@ func TestEVMTransaction(t *testing.T) { req, err = types.NewMsgEVMTransaction(txwrapper) require.Nil(t, err) ante.Preprocess(ctx, req) + ctx, err = ante.NewEVMFeeCheckDecorator(k).AnteHandle(ctx, mockTx{msgs: []sdk.Msg{req}}, false, func(sdk.Context, sdk.Tx, bool) (sdk.Context, error) { + return ctx, nil + }) + require.Nil(t, err) res, err = msgServer.EVMTransaction(sdk.WrapSDKContext(ctx), req) require.Nil(t, err) require.LessOrEqual(t, res.GasUsed, uint64(200000)) @@ -143,6 +164,10 @@ func TestEVMTransactionError(t *testing.T) { msgServer := keeper.NewMsgServerImpl(k) ante.Preprocess(ctx, req) + ctx, err = ante.NewEVMFeeCheckDecorator(k).AnteHandle(ctx, mockTx{msgs: []sdk.Msg{req}}, false, func(sdk.Context, sdk.Tx, bool) (sdk.Context, error) { + return ctx, nil + }) + require.Nil(t, err) res, err := msgServer.EVMTransaction(sdk.WrapSDKContext(ctx), req) require.Nil(t, err) // there should only be VM error, no msg-level error require.NotEmpty(t, res.VmError) @@ -194,9 +219,14 @@ func TestEVMTransactionInsufficientGas(t *testing.T) { // Deploy Simple Storage contract with insufficient gas ante.Preprocess(ctx, req) + ctx, err = ante.NewEVMFeeCheckDecorator(k).AnteHandle(ctx, mockTx{msgs: []sdk.Msg{req}}, false, func(sdk.Context, sdk.Tx, bool) (sdk.Context, error) { + return ctx, nil + }) + require.Nil(t, err) _, err = msgServer.EVMTransaction(sdk.WrapSDKContext(ctx), req) require.NotNil(t, err) - require.Contains(t, err.Error(), "intrinsic gas too low") // this can only happen in test because we didn't call CheckTx in this test + require.Contains(t, err.Error(), "intrinsic gas too low") // this can only happen in test because we didn't call CheckTx in this test + require.Equal(t, sdk.ZeroInt(), k.BankKeeper().GetBalance(ctx, evmAddr[:], k.GetBaseDenom(ctx)).Amount) // fee should be charged } func TestEVMDynamicFeeTransaction(t *testing.T) { @@ -237,6 +267,10 @@ func TestEVMDynamicFeeTransaction(t *testing.T) { // Deploy Simple Storage contract ante.Preprocess(ctx, req) + ctx, err = ante.NewEVMFeeCheckDecorator(k).AnteHandle(ctx, mockTx{msgs: []sdk.Msg{req}}, false, func(sdk.Context, sdk.Tx, bool) (sdk.Context, error) { + return ctx, nil + }) + require.Nil(t, err) res, err := msgServer.EVMTransaction(sdk.WrapSDKContext(ctx), req) require.Nil(t, err) require.LessOrEqual(t, res.GasUsed, uint64(200000)) @@ -290,6 +324,10 @@ func TestEVMPrecompiles(t *testing.T) { // Deploy SendAll contract ante.Preprocess(ctx, req) + ctx, err = ante.NewEVMFeeCheckDecorator(k).AnteHandle(ctx, mockTx{msgs: []sdk.Msg{req}}, false, func(sdk.Context, sdk.Tx, bool) (sdk.Context, error) { + return ctx, nil + }) + require.Nil(t, err) res, err := msgServer.EVMTransaction(sdk.WrapSDKContext(ctx), req) require.Nil(t, err) require.LessOrEqual(t, res.GasUsed, uint64(500000)) @@ -333,6 +371,10 @@ func TestEVMPrecompiles(t *testing.T) { req, err = types.NewMsgEVMTransaction(txwrapper) require.Nil(t, err) ante.Preprocess(ctx, req) + ctx, err = ante.NewEVMFeeCheckDecorator(k).AnteHandle(ctx, mockTx{msgs: []sdk.Msg{req}}, false, func(sdk.Context, sdk.Tx, bool) (sdk.Context, error) { + return ctx, nil + }) + require.Nil(t, err) res, err = msgServer.EVMTransaction(sdk.WrapSDKContext(ctx), req) require.Nil(t, err) require.LessOrEqual(t, res.GasUsed, uint64(200000)) @@ -397,6 +439,10 @@ func TestEVMBlockEnv(t *testing.T) { // Deploy Simple Storage contract ante.Preprocess(ctx, req) + ctx, err = ante.NewEVMFeeCheckDecorator(k).AnteHandle(ctx, mockTx{msgs: []sdk.Msg{req}}, false, func(sdk.Context, sdk.Tx, bool) (sdk.Context, error) { + return ctx, nil + }) + require.Nil(t, err) res, err := msgServer.EVMTransaction(sdk.WrapSDKContext(ctx), req) require.Nil(t, err) require.LessOrEqual(t, res.GasUsed, uint64(200000)) @@ -431,6 +477,10 @@ func TestEVMBlockEnv(t *testing.T) { req, err = types.NewMsgEVMTransaction(txwrapper) require.Nil(t, err) ante.Preprocess(ctx, req) + ctx, err = ante.NewEVMFeeCheckDecorator(k).AnteHandle(ctx, mockTx{msgs: []sdk.Msg{req}}, false, func(sdk.Context, sdk.Tx, bool) (sdk.Context, error) { + return ctx, nil + }) + require.Nil(t, err) res, err = msgServer.EVMTransaction(sdk.WrapSDKContext(ctx), req) require.Nil(t, err) require.LessOrEqual(t, res.GasUsed, uint64(200000)) diff --git a/x/evm/state/statedb.go b/x/evm/state/statedb.go index 4988b3e9b..29a61363c 100644 --- a/x/evm/state/statedb.go +++ b/x/evm/state/statedb.go @@ -53,6 +53,13 @@ func NewDBImpl(ctx sdk.Context, k EVMKeeper, simulation bool) *DBImpl { return s } +func (s *DBImpl) AddSurplus(surplus sdk.Int) { + if surplus.IsNil() || surplus.IsZero() { + return + } + s.tempStateCurrent.surplus = s.tempStateCurrent.surplus.Add(surplus) +} + func (s *DBImpl) DisableEvents() { s.eventsSuppressed = true } diff --git a/x/evm/types/config.go b/x/evm/types/config.go index ef235ae6b..1d3e2748f 100644 --- a/x/evm/types/config.go +++ b/x/evm/types/config.go @@ -8,6 +8,8 @@ import ( "github.com/sei-protocol/sei-chain/utils" ) +var CancunTime int64 = -1 + /* * XXBlock/Time fields indicate upgrade heights/timestamps. For example, a BerlinBlock @@ -45,7 +47,7 @@ func (cc ChainConfig) EthereumConfig(chainID *big.Int) *params.ChainConfig { func DefaultChainConfig() ChainConfig { return ChainConfig{ - CancunTime: 0, + CancunTime: CancunTime, PragueTime: -1, VerkleTime: -1, } From c5b0abdc8a8132d5154de0f32deec03fd932c23e Mon Sep 17 00:00:00 2001 From: codchen Date: Tue, 16 Apr 2024 18:48:22 +0800 Subject: [PATCH 16/17] Make ChainID a config instead of a param (#1548) --- aclmapping/evm/mappings_test.go | 4 +- app/ante_test.go | 2 +- app/app.go | 7 +- cmd/seid/cmd/root.go | 7 ++ evmrpc/info.go | 2 +- evmrpc/net.go | 2 +- evmrpc/send.go | 2 +- evmrpc/send_test.go | 4 +- evmrpc/setup_test.go | 5 +- evmrpc/simulate.go | 3 +- evmrpc/simulate_test.go | 8 +- evmrpc/tx.go | 2 +- evmrpc/txpool.go | 2 +- go.mod | 2 + go.sum | 3 + precompiles/bank/bank_test.go | 2 +- precompiles/distribution/distribution_test.go | 2 +- precompiles/gov/gov_test.go | 4 +- precompiles/ibc/ibc_test.go | 2 +- precompiles/pointer/pointer_test.go | 2 +- precompiles/staking/staking_test.go | 4 +- precompiles/wasmd/wasmd_test.go | 14 +-- proto/evm/params.proto | 12 +- x/evm/ante/fee.go | 2 +- x/evm/ante/fee_test.go | 2 +- x/evm/ante/preprocess_test.go | 2 +- x/evm/ante/sig_test.go | 4 +- x/evm/artifacts/native/artifacts_test.go | 2 +- x/evm/config/config.go | 29 +++++ x/evm/keeper/evm.go | 2 +- x/evm/keeper/genesis.go | 3 - x/evm/keeper/keeper.go | 5 +- x/evm/keeper/keeper_test.go | 5 +- x/evm/keeper/msg_server.go | 2 +- x/evm/keeper/msg_server_test.go | 12 +- x/evm/keeper/params.go | 4 +- x/evm/module.go | 2 +- x/evm/state/accesslist_test.go | 2 +- x/evm/types/message_evm_transaction_test.go | 7 +- x/evm/types/params.go | 20 ---- x/evm/types/params.pb.go | 111 ++++++------------ x/evm/types/params_test.go | 13 +- 42 files changed, 151 insertions(+), 175 deletions(-) create mode 100644 x/evm/config/config.go diff --git a/aclmapping/evm/mappings_test.go b/aclmapping/evm/mappings_test.go index fb56460aa..512d8d215 100644 --- a/aclmapping/evm/mappings_test.go +++ b/aclmapping/evm/mappings_test.go @@ -80,9 +80,9 @@ func (suite *KeeperTestSuite) buildSendMsgTo(to common.Address, amt *big.Int) *t To: &to, Value: amt, Data: []byte(""), - ChainID: suite.App.EvmKeeper.ChainID(suite.Ctx), + ChainID: suite.App.EvmKeeper.ChainID(), } - ethCfg := types.DefaultChainConfig().EthereumConfig(suite.App.EvmKeeper.ChainID(suite.Ctx)) + ethCfg := types.DefaultChainConfig().EthereumConfig(suite.App.EvmKeeper.ChainID()) signer := ethtypes.MakeSigner(ethCfg, big.NewInt(suite.Ctx.BlockHeight()), uint64(suite.Ctx.BlockTime().Unix())) tx := ethtypes.NewTx(&txData) tx, err := ethtypes.SignTx(tx, signer, suite.sender) diff --git a/app/ante_test.go b/app/ante_test.go index 608b97dee..687e34649 100644 --- a/app/ante_test.go +++ b/app/ante_test.go @@ -236,7 +236,7 @@ func TestEvmAnteErrorHandler(t *testing.T) { Data: []byte{}, Nonce: 1, // will cause ante error } - chainID := testkeeper.EVMTestApp.EvmKeeper.ChainID(ctx) + chainID := testkeeper.EVMTestApp.EvmKeeper.ChainID() chainCfg := evmtypes.DefaultChainConfig() ethCfg := chainCfg.EthereumConfig(chainID) blockNum := big.NewInt(ctx.BlockHeight()) diff --git a/app/app.go b/app/app.go index 2a3b57b2d..850be9215 100644 --- a/app/app.go +++ b/app/app.go @@ -122,6 +122,7 @@ import ( "github.com/sei-protocol/sei-chain/x/evm" evmante "github.com/sei-protocol/sei-chain/x/evm/ante" "github.com/sei-protocol/sei-chain/x/evm/blocktest" + evmconfig "github.com/sei-protocol/sei-chain/x/evm/config" evmkeeper "github.com/sei-protocol/sei-chain/x/evm/keeper" "github.com/sei-protocol/sei-chain/x/evm/querier" "github.com/sei-protocol/sei-chain/x/evm/replay" @@ -587,9 +588,13 @@ func New( wasmOpts..., ) + evmConfig, err := evmconfig.ReadConfig(appOpts) + if err != nil { + panic(fmt.Sprintf("error reading EVM config due to %s", err)) + } app.EvmKeeper = *evmkeeper.NewKeeper(keys[evmtypes.StoreKey], memKeys[evmtypes.MemStoreKey], app.GetSubspace(evmtypes.ModuleName), app.BankKeeper, &app.AccountKeeper, &app.StakingKeeper, - app.TransferKeeper, wasmkeeper.NewDefaultPermissionKeeper(app.WasmKeeper)) + app.TransferKeeper, wasmkeeper.NewDefaultPermissionKeeper(app.WasmKeeper), &evmConfig) app.evmRPCConfig, err = evmrpc.ReadConfig(appOpts) if err != nil { panic(fmt.Sprintf("error reading EVM config due to %s", err)) diff --git a/cmd/seid/cmd/root.go b/cmd/seid/cmd/root.go index 1d86266ad..7442512a7 100644 --- a/cmd/seid/cmd/root.go +++ b/cmd/seid/cmd/root.go @@ -39,6 +39,7 @@ import ( "github.com/sei-protocol/sei-chain/evmrpc" "github.com/sei-protocol/sei-chain/tools" "github.com/sei-protocol/sei-chain/x/evm/blocktest" + evmconfig "github.com/sei-protocol/sei-chain/x/evm/config" "github.com/sei-protocol/sei-chain/x/evm/querier" "github.com/sei-protocol/sei-chain/x/evm/replay" "github.com/spf13/cast" @@ -381,6 +382,8 @@ func initAppConfig() (string, interface{}) { ETHBlockTest blocktest.Config `mapstructure:"eth_block_test"` EvmQuery querier.Config `mapstructure:"evm_query"` + + EvmModule evmconfig.Config `mapstructure:"evm_module"` } // Optionally allow the chain developer to overwrite the SDK's default @@ -424,6 +427,7 @@ func initAppConfig() (string, interface{}) { ETHReplay: replay.DefaultConfig, ETHBlockTest: blocktest.DefaultConfig, EvmQuery: querier.DefaultConfig, + EvmModule: evmconfig.DefaultConfig, } customAppTemplate := serverconfig.DefaultConfigTemplate + ` @@ -503,6 +507,9 @@ eth_blocktest_test_data_path = "{{ .ETHBlockTest.TestDataPath }}" [evm_query] evm_query_gas_limit = {{ .EvmQuery.GasLimit }} + +[evm_module] +evm_chain_id = {{ .EvmModule.ChainID }} ` return customAppTemplate, customAppConfig diff --git a/evmrpc/info.go b/evmrpc/info.go index e165cc3cf..b6f71e219 100644 --- a/evmrpc/info.go +++ b/evmrpc/info.go @@ -46,7 +46,7 @@ func (i *InfoAPI) BlockNumber() hexutil.Uint64 { func (i *InfoAPI) ChainId() *hexutil.Big { startTime := time.Now() defer recordMetrics("eth_ChainId", startTime, true) - return (*hexutil.Big)(i.keeper.ChainID(i.ctxProvider(LatestCtxHeight))) + return (*hexutil.Big)(i.keeper.ChainID()) } func (i *InfoAPI) Coinbase() (common.Address, error) { diff --git a/evmrpc/net.go b/evmrpc/net.go index 9bc603cc8..a32f31c53 100644 --- a/evmrpc/net.go +++ b/evmrpc/net.go @@ -23,5 +23,5 @@ func NewNetAPI(tmClient rpcclient.Client, k *keeper.Keeper, ctxProvider func(int func (i *NetAPI) Version() string { startTime := time.Now() defer recordMetrics("net_version", startTime, true) - return fmt.Sprintf("%d", i.keeper.ChainID(i.ctxProvider(LatestCtxHeight)).Uint64()) + return fmt.Sprintf("%d", i.keeper.ChainID().Uint64()) } diff --git a/evmrpc/send.go b/evmrpc/send.go index ec388d84c..264df5b5e 100644 --- a/evmrpc/send.go +++ b/evmrpc/send.go @@ -134,7 +134,7 @@ func (s *SendAPI) signTransaction(unsignedTx *ethtypes.Transaction, from string) if !ok { return nil, errors.New("from address does not have hosted key") } - chainId := s.keeper.ChainID(s.ctxProvider(LatestCtxHeight)) + chainId := s.keeper.ChainID() signer := ethtypes.LatestSignerForChainID(chainId) return ethtypes.SignTx(unsignedTx, signer, privKey) } diff --git a/evmrpc/send_test.go b/evmrpc/send_test.go index 2f86cc790..6a4da6889 100644 --- a/evmrpc/send_test.go +++ b/evmrpc/send_test.go @@ -33,14 +33,14 @@ func TestSendRawTransaction(t *testing.T) { To: &to, Value: big.NewInt(1000), Data: []byte("abc"), - ChainID: EVMKeeper.ChainID(Ctx), + ChainID: EVMKeeper.ChainID(), } mnemonic := "fish mention unlock february marble dove vintage sand hub ordinary fade found inject room embark supply fabric improve spike stem give current similar glimpse" derivedPriv, _ := hd.Secp256k1.Derive()(mnemonic, "", "") privKey := hd.Secp256k1.Generate()(derivedPriv) testPrivHex := hex.EncodeToString(privKey.Bytes()) key, _ := crypto.HexToECDSA(testPrivHex) - ethCfg := types.DefaultChainConfig().EthereumConfig(EVMKeeper.ChainID(Ctx)) + ethCfg := types.DefaultChainConfig().EthereumConfig(EVMKeeper.ChainID()) signer := ethtypes.MakeSigner(ethCfg, big.NewInt(Ctx.BlockHeight()), uint64(Ctx.BlockTime().Unix())) tx := ethtypes.NewTx(&txData) tx, err := ethtypes.SignTx(tx, signer, key) diff --git a/evmrpc/setup_test.go b/evmrpc/setup_test.go index 5df8df331..1772f0684 100644 --- a/evmrpc/setup_test.go +++ b/evmrpc/setup_test.go @@ -25,6 +25,7 @@ import ( "github.com/sei-protocol/sei-chain/app" "github.com/sei-protocol/sei-chain/evmrpc" "github.com/sei-protocol/sei-chain/utils" + "github.com/sei-protocol/sei-chain/x/evm/config" "github.com/sei-protocol/sei-chain/x/evm/keeper" "github.com/sei-protocol/sei-chain/x/evm/types" evmtypes "github.com/sei-protocol/sei-chain/x/evm/types" @@ -449,7 +450,7 @@ func init() { } func generateTxData() { - chainId := big.NewInt(types.DefaultChainID.Int64()) + chainId := big.NewInt(config.DefaultConfig.ChainID) to := common.HexToAddress("010203") var txBuilder1, txBuilder1_5, txBuilder2, txBuilder3, txBuilder4 client.TxBuilder txBuilder1, tx1 = buildTx(ethtypes.DynamicFeeTx{ @@ -572,7 +573,7 @@ func generateTxData() { } func buildTx(txData ethtypes.DynamicFeeTx) (client.TxBuilder, *ethtypes.Transaction) { - chainId := big.NewInt(types.DefaultChainID.Int64()) + chainId := big.NewInt(config.DefaultConfig.ChainID) mnemonic := "fish mention unlock february marble dove vintage sand hub ordinary fade found inject room embark supply fabric improve spike stem give current similar glimpse" derivedPriv, _ := hd.Secp256k1.Derive()(mnemonic, "", "") privKey := hd.Secp256k1.Generate()(derivedPriv) diff --git a/evmrpc/simulate.go b/evmrpc/simulate.go index 8e82ef1b3..5fc664297 100644 --- a/evmrpc/simulate.go +++ b/evmrpc/simulate.go @@ -243,8 +243,7 @@ func (b *Backend) RPCGasCap() uint64 { return b.config.GasCap } func (b *Backend) RPCEVMTimeout() time.Duration { return b.config.EVMTimeout } func (b *Backend) ChainConfig() *params.ChainConfig { - ctx := b.ctxProvider(LatestCtxHeight) - return types.DefaultChainConfig().EthereumConfig(b.keeper.ChainID(ctx)) + return types.DefaultChainConfig().EthereumConfig(b.keeper.ChainID()) } func (b *Backend) GetPoolNonce(_ context.Context, addr common.Address) (uint64, error) { diff --git a/evmrpc/simulate_test.go b/evmrpc/simulate_test.go index 28b5a06f0..fb9e13dfc 100644 --- a/evmrpc/simulate_test.go +++ b/evmrpc/simulate_test.go @@ -26,7 +26,7 @@ func TestEstimateGas(t *testing.T) { "to": to.Hex(), "value": "0x10", "nonce": "0x1", - "chainId": fmt.Sprintf("%#x", EVMKeeper.ChainID(Ctx)), + "chainId": fmt.Sprintf("%#x", EVMKeeper.ChainID()), } amts := sdk.NewCoins(sdk.NewCoin(EVMKeeper.GetBaseDenom(Ctx), sdk.NewInt(20))) EVMKeeper.BankKeeper().MintCoins(Ctx, types.ModuleName, amts) @@ -57,7 +57,7 @@ func TestEstimateGas(t *testing.T) { "to": contractAddr.Hex(), "value": "0x0", "nonce": "0x2", - "chainId": fmt.Sprintf("%#x", EVMKeeper.ChainID(Ctx)), + "chainId": fmt.Sprintf("%#x", EVMKeeper.ChainID()), "input": fmt.Sprintf("%#x", input), } resObj = sendRequestGood(t, "estimateGas", txArgs, nil, map[string]interface{}{}) @@ -86,7 +86,7 @@ func TestCreateAccessList(t *testing.T) { "to": contractAddr.Hex(), "value": "0x0", "nonce": "0x1", - "chainId": fmt.Sprintf("%#x", EVMKeeper.ChainID(Ctx)), + "chainId": fmt.Sprintf("%#x", EVMKeeper.ChainID()), "input": fmt.Sprintf("%#x", input), } amts := sdk.NewCoins(sdk.NewCoin(EVMKeeper.GetBaseDenom(Ctx), sdk.NewInt(20))) @@ -122,7 +122,7 @@ func TestCall(t *testing.T) { "to": contractAddr.Hex(), "value": "0x0", "nonce": "0x2", - "chainId": fmt.Sprintf("%#x", EVMKeeper.ChainID(Ctx)), + "chainId": fmt.Sprintf("%#x", EVMKeeper.ChainID()), "input": fmt.Sprintf("%#x", input), } resObj := sendRequestGood(t, "call", txArgs, nil, map[string]interface{}{}, map[string]interface{}{}) diff --git a/evmrpc/tx.go b/evmrpc/tx.go index 3863506be..9f59bdda3 100644 --- a/evmrpc/tx.go +++ b/evmrpc/tx.go @@ -105,7 +105,7 @@ func (t *TransactionAPI) GetTransactionByHash(ctx context.Context, hash common.H etx := getEthTxForTxBz(tx, t.txConfig.TxDecoder()) if etx != nil && etx.Hash() == hash { signer := ethtypes.MakeSigner( - types.DefaultChainConfig().EthereumConfig(t.keeper.ChainID(sdkCtx)), + types.DefaultChainConfig().EthereumConfig(t.keeper.ChainID()), big.NewInt(sdkCtx.BlockHeight()), uint64(sdkCtx.BlockTime().Unix()), ) diff --git a/evmrpc/txpool.go b/evmrpc/txpool.go index 48f8f8f16..802bdbf7b 100644 --- a/evmrpc/txpool.go +++ b/evmrpc/txpool.go @@ -46,7 +46,7 @@ func (t *TxPoolAPI) Content(ctx context.Context) (result map[string]map[string]m sdkCtx := t.ctxProvider(LatestCtxHeight) signer := ethtypes.MakeSigner( - types.DefaultChainConfig().EthereumConfig(t.keeper.ChainID(sdkCtx)), + types.DefaultChainConfig().EthereumConfig(t.keeper.ChainID()), big.NewInt(sdkCtx.BlockHeight()), uint64(sdkCtx.BlockTime().Unix()), ) diff --git a/go.mod b/go.mod index f0057b3af..9554761d5 100644 --- a/go.mod +++ b/go.mod @@ -125,6 +125,7 @@ require ( github.com/fzipp/gocyclo v0.5.1 // indirect github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff // indirect github.com/gballet/go-verkle v0.1.1-0.20231031103413-a67434b50f46 // indirect + github.com/ghodss/yaml v1.0.0 // indirect github.com/go-critic/go-critic v0.6.3 // indirect github.com/go-kit/kit v0.12.0 // indirect github.com/go-kit/log v0.2.1 // indirect @@ -172,6 +173,7 @@ require ( github.com/gostaticanalysis/nilerr v0.1.1 // indirect github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 // indirect github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.1 // indirect github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c // indirect github.com/hashicorp/errwrap v1.0.0 // indirect github.com/hashicorp/go-bexpr v0.1.10 // indirect diff --git a/go.sum b/go.sum index ececc606f..f667aff62 100644 --- a/go.sum +++ b/go.sum @@ -457,6 +457,7 @@ github.com/gballet/go-verkle v0.1.1-0.20231031103413-a67434b50f46 h1:BAIP2Gihuqh github.com/gballet/go-verkle v0.1.1-0.20231031103413-a67434b50f46/go.mod h1:QNpY22eby74jVhqH4WhDLDwxc/vqsern6pW+u2kbkpc= github.com/getkin/kin-openapi v0.53.0/go.mod h1:7Yn5whZr5kJi6t+kShccXS8ae1APpYTW6yheSwk8Yi4= github.com/ghemawat/stream v0.0.0-20171120220530-696b145b53b9/go.mod h1:106OIgooyS7OzLDOpUGgm9fA3bQENb/cFSyyBmMoJDs= +github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= @@ -765,6 +766,8 @@ github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t github.com/grpc-ecosystem/grpc-gateway v1.12.1/go.mod h1:8XEsbTttt/W+VvjtQhLACqCisSPWTxCZ7sBRjU6iH9c= github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.1 h1:/c3QmbOGMGTOumP2iT/rCwB7b0QDGLKzqOmktBjT+Is= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.1/go.mod h1:5SN9VR2LTsRFsrEC6FHgRbTWrTHu6tqPeKxEQv15giM= github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c h1:6rhixN/i8ZofjG1Y75iExal34USq5p+wiN1tpie8IrU= github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c/go.mod h1:NMPJylDgVpX0MLRlPy15sqSwOFv/U1GZ2m21JhFfek0= github.com/guptarohit/asciigraph v0.5.5/go.mod h1:dYl5wwK4gNsnFf9Zp+l06rFiDZ5YtXM6x7SRWZ3KGag= diff --git a/precompiles/bank/bank_test.go b/precompiles/bank/bank_test.go index d8ad3e986..8552b3fd3 100644 --- a/precompiles/bank/bank_test.go +++ b/precompiles/bank/bank_test.go @@ -113,7 +113,7 @@ func TestRun(t *testing.T) { Data: argsNative, Nonce: 0, } - chainID := k.ChainID(ctx) + chainID := k.ChainID() chainCfg := types.DefaultChainConfig() ethCfg := chainCfg.EthereumConfig(chainID) blockNum := big.NewInt(ctx.BlockHeight()) diff --git a/precompiles/distribution/distribution_test.go b/precompiles/distribution/distribution_test.go index 179096125..3d27d57b2 100644 --- a/precompiles/distribution/distribution_test.go +++ b/precompiles/distribution/distribution_test.go @@ -55,7 +55,7 @@ func TestWithdraw(t *testing.T) { Data: args, Nonce: 0, } - chainID := k.ChainID(ctx) + chainID := k.ChainID() chainCfg := evmtypes.DefaultChainConfig() ethCfg := chainCfg.EthereumConfig(chainID) blockNum := big.NewInt(ctx.BlockHeight()) diff --git a/precompiles/gov/gov_test.go b/precompiles/gov/gov_test.go index 9e77c36af..d122e1d79 100644 --- a/precompiles/gov/gov_test.go +++ b/precompiles/gov/gov_test.go @@ -45,7 +45,7 @@ func TestVoteDeposit(t *testing.T) { Data: args, Nonce: 0, } - chainID := k.ChainID(ctx) + chainID := k.ChainID() chainCfg := evmtypes.DefaultChainConfig() ethCfg := chainCfg.EthereumConfig(chainID) blockNum := big.NewInt(ctx.BlockHeight()) @@ -90,7 +90,7 @@ func TestVoteDeposit(t *testing.T) { Data: args, Nonce: 0, } - chainID := k.ChainID(ctx) + chainID := k.ChainID() chainCfg := evmtypes.DefaultChainConfig() ethCfg := chainCfg.EthereumConfig(chainID) blockNum := big.NewInt(ctx.BlockHeight()) diff --git a/precompiles/ibc/ibc_test.go b/precompiles/ibc/ibc_test.go index 12579cc99..fc07b9cb8 100644 --- a/precompiles/ibc/ibc_test.go +++ b/precompiles/ibc/ibc_test.go @@ -93,7 +93,7 @@ func TestPrecompile_Run(t *testing.T) { fields: fields{transferKeeper: &MockTransferKeeper{}}, args: commonArgs, wantBz: packedTrue, - wantRemainingGas: 992974, + wantRemainingGas: 994040, wantErr: false, }, { diff --git a/precompiles/pointer/pointer_test.go b/precompiles/pointer/pointer_test.go index f621a66c3..eb893454f 100644 --- a/precompiles/pointer/pointer_test.go +++ b/precompiles/pointer/pointer_test.go @@ -24,7 +24,7 @@ func TestAddNative(t *testing.T) { ctx := testApp.GetContextForDeliverTx([]byte{}).WithBlockTime(time.Now()) _, caller := testkeeper.MockAddressPair() suppliedGas := uint64(10000000) - cfg := types.DefaultChainConfig().EthereumConfig(testApp.EvmKeeper.ChainID(ctx)) + cfg := types.DefaultChainConfig().EthereumConfig(testApp.EvmKeeper.ChainID()) // token has no metadata m, err := p.ABI.MethodById(p.AddNativePointerID) diff --git a/precompiles/staking/staking_test.go b/precompiles/staking/staking_test.go index 682dbcf2b..4f3253590 100644 --- a/precompiles/staking/staking_test.go +++ b/precompiles/staking/staking_test.go @@ -53,7 +53,7 @@ func TestStaking(t *testing.T) { Data: args, Nonce: 0, } - chainID := k.ChainID(ctx) + chainID := k.ChainID() chainCfg := evmtypes.DefaultChainConfig() ethCfg := chainCfg.EthereumConfig(chainID) blockNum := big.NewInt(ctx.BlockHeight()) @@ -162,7 +162,7 @@ func TestStakingError(t *testing.T) { Data: args, Nonce: 0, } - chainID := k.ChainID(ctx) + chainID := k.ChainID() chainCfg := evmtypes.DefaultChainConfig() ethCfg := chainCfg.EthereumConfig(chainID) blockNum := big.NewInt(ctx.BlockHeight()) diff --git a/precompiles/wasmd/wasmd_test.go b/precompiles/wasmd/wasmd_test.go index 9322386fc..0950d14c5 100644 --- a/precompiles/wasmd/wasmd_test.go +++ b/precompiles/wasmd/wasmd_test.go @@ -78,7 +78,7 @@ func TestInstantiate(t *testing.T) { require.Equal(t, 2, len(outputs)) require.Equal(t, "sei1hrpna9v7vs3stzyd4z3xf00676kf78zpe2u5ksvljswn2vnjp3yslucc3n", outputs[0].(string)) require.Empty(t, outputs[1].([]byte)) - require.Equal(t, uint64(879782), g) + require.Equal(t, uint64(880848), g) amtsbz, err = sdk.NewCoins().MarshalJSON() require.Nil(t, err) @@ -101,7 +101,7 @@ func TestInstantiate(t *testing.T) { require.Equal(t, 2, len(outputs)) require.Equal(t, "sei1hrpna9v7vs3stzyd4z3xf00676kf78zpe2u5ksvljswn2vnjp3yslucc3n", outputs[0].(string)) require.Empty(t, outputs[1].([]byte)) - require.Equal(t, uint64(902838), g) + require.Equal(t, uint64(903904), g) // non-existent code ID args, _ = instantiateMethod.Inputs.Pack( @@ -162,7 +162,7 @@ func TestExecute(t *testing.T) { require.Nil(t, err) require.Equal(t, 1, len(outputs)) require.Equal(t, fmt.Sprintf("received test msg from %s with 1000usei", mockAddr.String()), string(outputs[0].([]byte))) - require.Equal(t, uint64(906041), g) + require.Equal(t, uint64(907107), g) require.Equal(t, int64(1000), testApp.BankKeeper.GetBalance(statedb.Ctx(), contractAddr, "usei").Amount.Int64()) amtsbz, err = sdk.NewCoins().MarshalJSON() @@ -242,7 +242,7 @@ func TestQuery(t *testing.T) { require.Nil(t, err) require.Equal(t, 1, len(outputs)) require.Equal(t, "{\"message\":\"query test\"}", string(outputs[0].([]byte))) - require.Equal(t, uint64(930367), g) + require.Equal(t, uint64(931433), g) // bad contract address args, _ = queryMethod.Inputs.Pack(mockAddr.String(), []byte("{\"info\":{}}")) @@ -304,7 +304,7 @@ func TestExecuteBatchOneMessage(t *testing.T) { require.Nil(t, err) require.Equal(t, 1, len(outputs)) require.Equal(t, fmt.Sprintf("received test msg from %s with 1000usei", mockAddr.String()), string((outputs[0].([][]byte))[0])) - require.Equal(t, uint64(906041), g) + require.Equal(t, uint64(907107), g) require.Equal(t, int64(1000), testApp.BankKeeper.GetBalance(statedb.Ctx(), contractAddr, "usei").Amount.Int64()) amtsbz, err = sdk.NewCoins().MarshalJSON() @@ -409,7 +409,7 @@ func TestExecuteBatchMultipleMessages(t *testing.T) { require.Equal(t, fmt.Sprintf("received test msg from %s with 1000usei", mockAddr.String()), string(parsedOutputs[0])) require.Equal(t, fmt.Sprintf("received test msg from %s with 1000usei", mockAddr.String()), string(parsedOutputs[1])) require.Equal(t, fmt.Sprintf("received test msg from %s with 1000usei", mockAddr.String()), string(parsedOutputs[2])) - require.Equal(t, uint64(725379), g) + require.Equal(t, uint64(726445), g) require.Equal(t, int64(3000), testApp.BankKeeper.GetBalance(statedb.Ctx(), contractAddr, "usei").Amount.Int64()) amtsbz2, err := sdk.NewCoins().MarshalJSON() @@ -436,7 +436,7 @@ func TestExecuteBatchMultipleMessages(t *testing.T) { require.Equal(t, fmt.Sprintf("received test msg from %s with", mockAddr.String()), string(parsedOutputs[0])) require.Equal(t, fmt.Sprintf("received test msg from %s with 1000usei", mockAddr.String()), string(parsedOutputs[1])) require.Equal(t, fmt.Sprintf("received test msg from %s with", mockAddr.String()), string(parsedOutputs[2])) - require.Equal(t, uint64(773900), g) + require.Equal(t, uint64(774966), g) require.Equal(t, int64(1000), testApp.BankKeeper.GetBalance(statedb.Ctx(), contractAddr, "usei").Amount.Int64()) // allowed delegatecall diff --git a/proto/evm/params.proto b/proto/evm/params.proto index 5bdfb7221..3f07c1a07 100644 --- a/proto/evm/params.proto +++ b/proto/evm/params.proto @@ -33,12 +33,12 @@ string minimum_fee_per_gas = 4 [ (gogoproto.jsontag) = "minimum_fee_per_gas" ]; // ChainConfig chain_config = 5 [(gogoproto.moretags) = "yaml:\"chain_config\"", (gogoproto.nullable) = false]; - string chain_id = 6 [ - (gogoproto.moretags) = "yaml:\"chain_id\"", - (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", - (gogoproto.nullable) = false, - (gogoproto.jsontag) = "chain_id" -]; +// string chain_id = 6 [ +// (gogoproto.moretags) = "yaml:\"chain_id\"", +// (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", +// (gogoproto.nullable) = false, +// (gogoproto.jsontag) = "chain_id" +// ]; // repeated string whitelisted_codehashes_bank_send = 7 [ // (gogoproto.moretags) = "yaml:\"whitelisted_codehashes_bank_send\"", // (gogoproto.jsontag) = "whitelisted_codehashes_bank_send" diff --git a/x/evm/ante/fee.go b/x/evm/ante/fee.go index 1e64bd920..10988e0b3 100644 --- a/x/evm/ante/fee.go +++ b/x/evm/ante/fee.go @@ -66,7 +66,7 @@ func (fc EVMFeeCheckDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate b if err != nil { return ctx, err } - cfg := evmtypes.DefaultChainConfig().EthereumConfig(fc.evmKeeper.ChainID(ctx)) + cfg := evmtypes.DefaultChainConfig().EthereumConfig(fc.evmKeeper.ChainID()) txCtx := core.NewEVMTxContext(emsg) evmInstance := vm.NewEVM(*blockCtx, txCtx, stateDB, cfg, vm.Config{}) stateDB.SetEVM(evmInstance) diff --git a/x/evm/ante/fee_test.go b/x/evm/ante/fee_test.go index 8b47c980e..23f780d3d 100644 --- a/x/evm/ante/fee_test.go +++ b/x/evm/ante/fee_test.go @@ -27,7 +27,7 @@ func TestEVMFeeCheckDecorator(t *testing.T) { key, _ := crypto.HexToECDSA(testPrivHex) to := new(common.Address) copy(to[:], []byte("0x1234567890abcdef1234567890abcdef12345678")) - chainID := k.ChainID(ctx) + chainID := k.ChainID() txData := ethtypes.DynamicFeeTx{ Nonce: 0, GasFeeCap: big.NewInt(10000000000000), diff --git a/x/evm/ante/preprocess_test.go b/x/evm/ante/preprocess_test.go index cdc39ce95..f687b2c8f 100644 --- a/x/evm/ante/preprocess_test.go +++ b/x/evm/ante/preprocess_test.go @@ -44,7 +44,7 @@ func TestPreprocessAnteHandler(t *testing.T) { Value: big.NewInt(1000), Data: []byte("abc"), } - chainID := k.ChainID(ctx) + chainID := k.ChainID() chainCfg := types.DefaultChainConfig() ethCfg := chainCfg.EthereumConfig(chainID) blockNum := big.NewInt(ctx.BlockHeight()) diff --git a/x/evm/ante/sig_test.go b/x/evm/ante/sig_test.go index 5580d24be..746cdd8e6 100644 --- a/x/evm/ante/sig_test.go +++ b/x/evm/ante/sig_test.go @@ -33,7 +33,7 @@ func TestEVMSigVerifyDecorator(t *testing.T) { Value: big.NewInt(1000), Data: []byte("abc"), } - chainID := k.ChainID(ctx) + chainID := k.ChainID() chainCfg := types.DefaultChainConfig() ethCfg := chainCfg.EthereumConfig(chainID) blockNum := big.NewInt(ctx.BlockHeight()) @@ -109,7 +109,7 @@ func TestSigVerifyPendingTransaction(t *testing.T) { Value: big.NewInt(1000), Data: []byte("abc"), } - chainID := k.ChainID(ctx) + chainID := k.ChainID() chainCfg := types.DefaultChainConfig() ethCfg := chainCfg.EthereumConfig(chainID) blockNum := big.NewInt(ctx.BlockHeight()) diff --git a/x/evm/artifacts/native/artifacts_test.go b/x/evm/artifacts/native/artifacts_test.go index e023def9b..88f15e6e3 100644 --- a/x/evm/artifacts/native/artifacts_test.go +++ b/x/evm/artifacts/native/artifacts_test.go @@ -41,7 +41,7 @@ func TestSimple(t *testing.T) { Data: contractData, Nonce: 0, } - chainID := k.ChainID(ctx) + chainID := k.ChainID() chainCfg := types.DefaultChainConfig() ethCfg := chainCfg.EthereumConfig(chainID) blockNum := big.NewInt(ctx.BlockHeight()) diff --git a/x/evm/config/config.go b/x/evm/config/config.go new file mode 100644 index 000000000..8722424c2 --- /dev/null +++ b/x/evm/config/config.go @@ -0,0 +1,29 @@ +package config + +import ( + servertypes "github.com/cosmos/cosmos-sdk/server/types" + "github.com/spf13/cast" +) + +type Config struct { + ChainID int64 `mapstructure:"evm_chain_id"` +} + +var DefaultConfig = Config{ + ChainID: 713715, +} + +const ( + flagChainID = "evm_module.evm_chain_id" +) + +func ReadConfig(opts servertypes.AppOptions) (Config, error) { + cfg := DefaultConfig // copy + var err error + if v := opts.Get(flagChainID); v != nil { + if cfg.ChainID, err = cast.ToInt64E(v); err != nil { + return cfg, err + } + } + return cfg, nil +} diff --git a/x/evm/keeper/evm.go b/x/evm/keeper/evm.go index 3bce9a770..6db6c419a 100644 --- a/x/evm/keeper/evm.go +++ b/x/evm/keeper/evm.go @@ -136,7 +136,7 @@ func (k *Keeper) getOrCreateEVM(ctx sdk.Context, from sdk.AccAddress) (*vm.EVM, if err != nil { return nil, nil, err } - cfg := types.DefaultChainConfig().EthereumConfig(k.ChainID(executionCtx)) + cfg := types.DefaultChainConfig().EthereumConfig(k.ChainID()) txCtx := vm.TxContext{Origin: k.GetEVMAddressOrDefault(ctx, from)} evm = vm.NewEVM(*blockCtx, txCtx, stateDB, cfg, vm.Config{}) stateDB.SetEVM(evm) diff --git a/x/evm/keeper/genesis.go b/x/evm/keeper/genesis.go index dc46d5ac7..a1a8606fc 100644 --- a/x/evm/keeper/genesis.go +++ b/x/evm/keeper/genesis.go @@ -55,9 +55,6 @@ func (k *Keeper) InitGenesis(ctx sdk.Context, genState types.GenesisState) { if k.EthReplayConfig.Enabled && !ethReplayInitialied { header := k.OpenEthDatabase() - params := k.GetParams(ctx) - params.ChainId = sdk.OneInt() - k.SetParams(ctx, params) k.SetReplayInitialHeight(ctx, header.Number.Int64()) ethReplayInitialied = true } diff --git a/x/evm/keeper/keeper.go b/x/evm/keeper/keeper.go index 209732843..426ae6165 100644 --- a/x/evm/keeper/keeper.go +++ b/x/evm/keeper/keeper.go @@ -33,6 +33,7 @@ import ( "github.com/sei-protocol/sei-chain/utils" "github.com/sei-protocol/sei-chain/x/evm/blocktest" + "github.com/sei-protocol/sei-chain/x/evm/config" "github.com/sei-protocol/sei-chain/x/evm/querier" "github.com/sei-protocol/sei-chain/x/evm/replay" "github.com/sei-protocol/sei-chain/x/evm/state" @@ -59,6 +60,7 @@ type Keeper struct { pendingTxs map[string][]*PendingTx keyToNonce map[tmtypes.TxKey]*AddressNoncePair + Config *config.Config QueryConfig *querier.Config // only used during ETH replay. Not used in chain critical path. @@ -115,7 +117,7 @@ func (ctx *ReplayChainContext) GetHeader(hash common.Hash, number uint64) *ethty func NewKeeper( storeKey sdk.StoreKey, memStoreKey sdk.StoreKey, paramstore paramtypes.Subspace, bankKeeper bankkeeper.Keeper, accountKeeper *authkeeper.AccountKeeper, stakingKeeper *stakingkeeper.Keeper, - transferKeeper ibctransferkeeper.Keeper, wasmKeeper *wasmkeeper.PermissionedKeeper) *Keeper { + transferKeeper ibctransferkeeper.Keeper, wasmKeeper *wasmkeeper.PermissionedKeeper, conf *config.Config) *Keeper { if !paramstore.HasKeyTable() { paramstore = paramstore.WithKeyTable(types.ParamKeyTable()) } @@ -133,6 +135,7 @@ func NewKeeper( cachedFeeCollectorAddressMtx: &sync.RWMutex{}, keyToNonce: make(map[tmtypes.TxKey]*AddressNoncePair), deferredInfo: &sync.Map{}, + Config: conf, } return k } diff --git a/x/evm/keeper/keeper_test.go b/x/evm/keeper/keeper_test.go index 9da18560f..5df83bd7e 100644 --- a/x/evm/keeper/keeper_test.go +++ b/x/evm/keeper/keeper_test.go @@ -10,6 +10,7 @@ import ( "github.com/ethereum/go-ethereum/common" ethtypes "github.com/ethereum/go-ethereum/core/types" "github.com/sei-protocol/sei-chain/testutil/keeper" + "github.com/sei-protocol/sei-chain/x/evm/config" evmkeeper "github.com/sei-protocol/sei-chain/x/evm/keeper" "github.com/sei-protocol/sei-chain/x/evm/types" "github.com/stretchr/testify/require" @@ -30,8 +31,8 @@ func TestPurgePrefixNotHang(t *testing.T) { } func TestGetChainID(t *testing.T) { - k, ctx := keeper.MockEVMKeeper() - require.Equal(t, types.DefaultChainID.Int64(), k.ChainID(ctx).Int64()) + k, _ := keeper.MockEVMKeeper() + require.Equal(t, config.DefaultConfig.ChainID, k.ChainID().Int64()) } func TestGetVMBlockContext(t *testing.T) { diff --git a/x/evm/keeper/msg_server.go b/x/evm/keeper/msg_server.go index 78ea4ab86..29ad789fa 100644 --- a/x/evm/keeper/msg_server.go +++ b/x/evm/keeper/msg_server.go @@ -196,7 +196,7 @@ func (server msgServer) applyEVMMessage(ctx sdk.Context, msg *core.Message, stat if err != nil { return nil, err } - cfg := types.DefaultChainConfig().EthereumConfig(server.ChainID(ctx)) + cfg := types.DefaultChainConfig().EthereumConfig(server.ChainID()) txCtx := core.NewEVMTxContext(msg) evmInstance := vm.NewEVM(*blockCtx, txCtx, stateDB, cfg, vm.Config{}) stateDB.SetEVM(evmInstance) diff --git a/x/evm/keeper/msg_server_test.go b/x/evm/keeper/msg_server_test.go index 5d1fc24ea..99823375a 100644 --- a/x/evm/keeper/msg_server_test.go +++ b/x/evm/keeper/msg_server_test.go @@ -55,7 +55,7 @@ func TestEVMTransaction(t *testing.T) { Data: bz, Nonce: 0, } - chainID := k.ChainID(ctx) + chainID := k.ChainID() chainCfg := types.DefaultChainConfig() ethCfg := chainCfg.EthereumConfig(chainID) blockNum := big.NewInt(ctx.BlockHeight()) @@ -144,7 +144,7 @@ func TestEVMTransactionError(t *testing.T) { Data: []byte("123090321920390920123"), // gibberish data Nonce: 0, } - chainID := k.ChainID(ctx) + chainID := k.ChainID() chainCfg := types.DefaultChainConfig() ethCfg := chainCfg.EthereumConfig(chainID) blockNum := big.NewInt(ctx.BlockHeight()) @@ -198,7 +198,7 @@ func TestEVMTransactionInsufficientGas(t *testing.T) { Data: bz, Nonce: 0, } - chainID := k.ChainID(ctx) + chainID := k.ChainID() chainCfg := types.DefaultChainConfig() ethCfg := chainCfg.EthereumConfig(chainID) blockNum := big.NewInt(ctx.BlockHeight()) @@ -246,7 +246,7 @@ func TestEVMDynamicFeeTransaction(t *testing.T) { Data: bz, Nonce: 0, } - chainID := k.ChainID(ctx) + chainID := k.ChainID() chainCfg := types.DefaultChainConfig() ethCfg := chainCfg.EthereumConfig(chainID) blockNum := big.NewInt(ctx.BlockHeight()) @@ -303,7 +303,7 @@ func TestEVMPrecompiles(t *testing.T) { Data: bz, Nonce: 0, } - chainID := k.ChainID(ctx) + chainID := k.ChainID() chainCfg := types.DefaultChainConfig() ethCfg := chainCfg.EthereumConfig(chainID) blockNum := big.NewInt(ctx.BlockHeight()) @@ -418,7 +418,7 @@ func TestEVMBlockEnv(t *testing.T) { Data: bz, Nonce: 0, } - chainID := k.ChainID(ctx) + chainID := k.ChainID() chainCfg := types.DefaultChainConfig() ethCfg := chainCfg.EthereumConfig(chainID) blockNum := big.NewInt(ctx.BlockHeight()) diff --git a/x/evm/keeper/params.go b/x/evm/keeper/params.go index 81c821f0c..98107d36a 100644 --- a/x/evm/keeper/params.go +++ b/x/evm/keeper/params.go @@ -36,12 +36,12 @@ func (k *Keeper) GetMinimumFeePerGas(ctx sdk.Context) sdk.Dec { return k.GetParams(ctx).MinimumFeePerGas } -func (k *Keeper) ChainID(ctx sdk.Context) *big.Int { +func (k *Keeper) ChainID() *big.Int { if k.EthReplayConfig.Enabled || k.EthBlockTestConfig.Enabled { // replay is for eth mainnet so always return 1 return utils.Big1 } - return k.GetParams(ctx).ChainId.BigInt() + return big.NewInt(k.Config.ChainID) } func (k *Keeper) WhitelistedCwCodeHashesForDelegateCall(ctx sdk.Context) [][]byte { diff --git a/x/evm/module.go b/x/evm/module.go index 208038fdb..2e1ec5606 100644 --- a/x/evm/module.go +++ b/x/evm/module.go @@ -184,7 +184,7 @@ func (am AppModule) BeginBlock(ctx sdk.Context, _ abci.RequestBeginBlock) { panic(err) } statedb := state.NewDBImpl(ctx, am.keeper, false) - vmenv := vm.NewEVM(*blockCtx, vm.TxContext{}, statedb, types.DefaultChainConfig().EthereumConfig(am.keeper.ChainID(ctx)), vm.Config{}) + vmenv := vm.NewEVM(*blockCtx, vm.TxContext{}, statedb, types.DefaultChainConfig().EthereumConfig(am.keeper.ChainID()), vm.Config{}) core.ProcessBeaconBlockRoot(*beaconRoot, vmenv, statedb) _, err = statedb.Finalize() if err != nil { diff --git a/x/evm/state/accesslist_test.go b/x/evm/state/accesslist_test.go index 9b6fe1e47..dc455f73f 100644 --- a/x/evm/state/accesslist_test.go +++ b/x/evm/state/accesslist_test.go @@ -77,7 +77,7 @@ func TestPrepare(t *testing.T) { }, }, } - shanghai := params.Rules{ChainID: k.ChainID(ctx), IsShanghai: true} + shanghai := params.Rules{ChainID: k.ChainID(), IsShanghai: true} statedb.Prepare( shanghai, sender, coinbase, &dest, precompiles, txaccesses, ) diff --git a/x/evm/types/message_evm_transaction_test.go b/x/evm/types/message_evm_transaction_test.go index 4303f4c78..bf780e25e 100644 --- a/x/evm/types/message_evm_transaction_test.go +++ b/x/evm/types/message_evm_transaction_test.go @@ -2,14 +2,15 @@ package types_test import ( "encoding/hex" + "math/big" + "testing" + wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types" sdk "github.com/cosmos/cosmos-sdk/types" ethtypes "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/sei-protocol/sei-chain/app" testkeeper "github.com/sei-protocol/sei-chain/testutil/keeper" - "math/big" - "testing" "github.com/ethereum/go-ethereum/common" "github.com/sei-protocol/sei-chain/x/evm/derived" @@ -35,7 +36,7 @@ func TestIsNotAssociate(t *testing.T) { func TestAsTransaction(t *testing.T) { k, ctx := testkeeper.MockEVMKeeper() - chainID := k.ChainID(ctx) + chainID := k.ChainID() chainCfg := types.DefaultChainConfig() ethCfg := chainCfg.EthereumConfig(chainID) blockNum := big.NewInt(ctx.BlockHeight()) diff --git a/x/evm/types/params.go b/x/evm/types/params.go index da1f1de8a..ff99431f5 100644 --- a/x/evm/types/params.go +++ b/x/evm/types/params.go @@ -14,7 +14,6 @@ var ( KeyPriorityNormalizer = []byte("KeyPriorityNormalizer") KeyBaseFeePerGas = []byte("KeyBaseFeePerGas") KeyMinFeePerGas = []byte("KeyMinFeePerGas") - KeyChainID = []byte("KeyChainID") KeyWhitelistedCwCodeHashesForDelegateCall = []byte("KeyWhitelistedCwCodeHashesForDelegateCall") ) @@ -25,7 +24,6 @@ var DefaultPriorityNormalizer = sdk.NewDec(1) // Ethereum). var DefaultBaseFeePerGas = sdk.NewDec(0) var DefaultMinFeePerGas = sdk.NewDec(1000000000) -var DefaultChainID = sdk.NewInt(713715) var DefaultWhitelistedCwCodeHashesForDelegateCall = generateDefaultWhitelistedCwCodeHashesForDelegateCall() @@ -40,7 +38,6 @@ func DefaultParams() Params { PriorityNormalizer: DefaultPriorityNormalizer, BaseFeePerGas: DefaultBaseFeePerGas, MinimumFeePerGas: DefaultMinFeePerGas, - ChainId: DefaultChainID, WhitelistedCwCodeHashesForDelegateCall: DefaultWhitelistedCwCodeHashesForDelegateCall, } } @@ -50,7 +47,6 @@ func (p *Params) ParamSetPairs() paramtypes.ParamSetPairs { paramtypes.NewParamSetPair(KeyPriorityNormalizer, &p.PriorityNormalizer, validatePriorityNormalizer), paramtypes.NewParamSetPair(KeyBaseFeePerGas, &p.BaseFeePerGas, validateBaseFeePerGas), paramtypes.NewParamSetPair(KeyMinFeePerGas, &p.MinimumFeePerGas, validateMinFeePerGas), - paramtypes.NewParamSetPair(KeyChainID, &p.ChainId, validateChainID), paramtypes.NewParamSetPair(KeyWhitelistedCwCodeHashesForDelegateCall, &p.WhitelistedCwCodeHashesForDelegateCall, validateWhitelistedCwHashesForDelegateCall), } } @@ -68,9 +64,6 @@ func (p Params) Validate() error { if p.MinimumFeePerGas.LT(p.BaseFeePerGas) { return errors.New("minimum fee cannot be lower than base fee") } - if err := validateChainID(p.ChainId); err != nil { - return err - } return validateWhitelistedCwHashesForDelegateCall(p.WhitelistedCwCodeHashesForDelegateCall) } @@ -118,19 +111,6 @@ func validateMinFeePerGas(i interface{}) error { return nil } -func validateChainID(i interface{}) error { - v, ok := i.(sdk.Int) - if !ok { - return fmt.Errorf("invalid parameter type: %T", i) - } - - if v.IsNegative() { - return fmt.Errorf("negative chain ID: %d", v) - } - - return nil -} - func validateWhitelistedCwHashesForDelegateCall(i interface{}) error { _, ok := i.([][]byte) if !ok { diff --git a/x/evm/types/params.pb.go b/x/evm/types/params.pb.go index ebd0b5f36..3f16118ba 100644 --- a/x/evm/types/params.pb.go +++ b/x/evm/types/params.pb.go @@ -34,7 +34,12 @@ type Params struct { BaseFeePerGas github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,3,opt,name=base_fee_per_gas,json=baseFeePerGas,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"base_fee_per_gas" yaml:"base_fee_per_gas"` MinimumFeePerGas github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,4,opt,name=minimum_fee_per_gas,json=minimumFeePerGas,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"minimum_fee_per_gas" yaml:"minimum_fee_per_gas"` // ChainConfig chain_config = 5 [(gogoproto.moretags) = "yaml:\"chain_config\"", (gogoproto.nullable) = false]; - ChainId github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,6,opt,name=chain_id,json=chainId,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"chain_id" yaml:"chain_id"` + // string chain_id = 6 [ + // (gogoproto.moretags) = "yaml:\"chain_id\"", + // (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", + // (gogoproto.nullable) = false, + // (gogoproto.jsontag) = "chain_id" + // ]; // repeated string whitelisted_codehashes_bank_send = 7 [ // (gogoproto.moretags) = "yaml:\"whitelisted_codehashes_bank_send\"", // (gogoproto.jsontag) = "whitelisted_codehashes_bank_send" @@ -88,36 +93,34 @@ func init() { func init() { proto.RegisterFile("evm/params.proto", fileDescriptor_9272f3679901ea94) } var fileDescriptor_9272f3679901ea94 = []byte{ - // 459 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x93, 0xb1, 0x6f, 0xd3, 0x40, - 0x18, 0xc5, 0x6d, 0x5a, 0x42, 0xb1, 0x40, 0x44, 0x2e, 0x12, 0x56, 0x06, 0x5f, 0xe5, 0xa1, 0xea, - 0x40, 0xec, 0xa1, 0x5b, 0xc7, 0xa4, 0x6a, 0xe9, 0x00, 0xaa, 0x3c, 0x22, 0xa1, 0xd3, 0xe5, 0xfc, - 0xc5, 0x3e, 0x71, 0xe7, 0xb3, 0xee, 0xdc, 0x86, 0xf0, 0x07, 0x30, 0x23, 0xc4, 0xc0, 0xc8, 0x3f, - 0x83, 0xd4, 0xb1, 0x23, 0x62, 0x38, 0xa1, 0x64, 0xcb, 0x18, 0x89, 0x1d, 0xe5, 0x9c, 0xb4, 0x05, - 0xb2, 0x84, 0xc9, 0x9f, 0xdf, 0xfb, 0xee, 0xf9, 0xa7, 0x67, 0x9d, 0xd7, 0x86, 0x4b, 0x91, 0x54, - 0x44, 0x11, 0xa1, 0xe3, 0x4a, 0xc9, 0x5a, 0xfa, 0x81, 0x06, 0x66, 0x27, 0x2a, 0x79, 0xac, 0x81, - 0xd1, 0x82, 0xb0, 0x32, 0x86, 0x4b, 0xd1, 0x79, 0x9a, 0xcb, 0x5c, 0x5a, 0x2b, 0x59, 0x4c, 0xcd, - 0x7e, 0xc7, 0x26, 0x50, 0x59, 0x0e, 0x59, 0xde, 0x28, 0xd1, 0xaf, 0xfb, 0x5e, 0xeb, 0xdc, 0x46, - 0xfa, 0x9f, 0x5d, 0x6f, 0xb7, 0x52, 0x4c, 0x2a, 0x56, 0x8f, 0x71, 0x29, 0x95, 0x20, 0x9c, 0xbd, - 0x07, 0x15, 0xdc, 0xdb, 0x73, 0x0f, 0x1e, 0xf6, 0xe8, 0x95, 0x41, 0xce, 0x0f, 0x83, 0xf6, 0x73, - 0x56, 0x17, 0x17, 0x83, 0x98, 0xca, 0x45, 0x92, 0x16, 0x52, 0x2f, 0x1f, 0x5d, 0x9d, 0xbd, 0x4d, - 0xea, 0x71, 0x05, 0x3a, 0x3e, 0x06, 0x3a, 0x33, 0x68, 0x5d, 0xd8, 0xdc, 0xa0, 0xce, 0x98, 0x08, - 0x7e, 0x14, 0xad, 0x31, 0xa3, 0xd4, 0x5f, 0xa9, 0xaf, 0x6e, 0x44, 0xff, 0x83, 0xeb, 0xb5, 0x07, - 0x44, 0x03, 0x1e, 0x02, 0xe0, 0x0a, 0x14, 0xce, 0x89, 0x0e, 0xb6, 0x2c, 0xd3, 0x9b, 0x8d, 0x99, - 0xfe, 0x49, 0x9a, 0x1b, 0xf4, 0xac, 0x01, 0xfa, 0xdb, 0x89, 0xd2, 0xc7, 0x0b, 0xe9, 0x04, 0xe0, - 0x1c, 0xd4, 0x29, 0xd1, 0xfe, 0x27, 0xd7, 0xdb, 0x15, 0xac, 0x64, 0xe2, 0x42, 0xfc, 0xc1, 0xb2, - 0xfd, 0xbf, 0xfd, 0xac, 0x09, 0xbb, 0xed, 0x67, 0x8d, 0x19, 0xa5, 0xed, 0xa5, 0x7a, 0x0b, 0x55, - 0x78, 0x3b, 0xf6, 0xa7, 0x63, 0x96, 0x05, 0x2d, 0x0b, 0xf2, 0x72, 0x03, 0x90, 0xb3, 0xb2, 0x9e, - 0x19, 0x74, 0x93, 0x30, 0x37, 0xe8, 0x49, 0xf3, 0xf5, 0x95, 0x12, 0xa5, 0x0f, 0xec, 0x78, 0x96, - 0xf9, 0xdf, 0x5c, 0xef, 0xf9, 0xa8, 0x60, 0x35, 0x70, 0xa6, 0x6b, 0xc8, 0x30, 0x1d, 0x61, 0x2a, - 0x33, 0xc0, 0x05, 0xd1, 0x05, 0x68, 0x3c, 0x94, 0x0a, 0x67, 0xc0, 0x21, 0x27, 0x35, 0x60, 0x4a, - 0x38, 0x0f, 0x76, 0xf6, 0xb6, 0x0e, 0x1e, 0xf5, 0xf2, 0x99, 0x41, 0x1b, 0x9d, 0x9b, 0x1b, 0x74, - 0xd8, 0x40, 0x6c, 0x72, 0x2a, 0x4a, 0xf7, 0xef, 0xac, 0xf7, 0x47, 0x7d, 0x99, 0xc1, 0x0b, 0xbb, - 0x7b, 0x22, 0xd5, 0xf1, 0x72, 0xb3, 0x4f, 0x38, 0x3f, 0xda, 0xfe, 0xf2, 0x15, 0x39, 0xbd, 0xd3, - 0xab, 0x49, 0xe8, 0x5e, 0x4f, 0x42, 0xf7, 0xe7, 0x24, 0x74, 0x3f, 0x4e, 0x43, 0xe7, 0x7a, 0x1a, - 0x3a, 0xdf, 0xa7, 0xa1, 0xf3, 0xba, 0x7b, 0xa7, 0x37, 0x0d, 0xac, 0xbb, 0xba, 0x5f, 0xf6, 0xc5, - 0x96, 0x91, 0xbc, 0x4b, 0x16, 0xf7, 0xc8, 0x56, 0x38, 0x68, 0x59, 0xff, 0xf0, 0x77, 0x00, 0x00, - 0x00, 0xff, 0xff, 0x44, 0xc2, 0x9d, 0x94, 0x9d, 0x03, 0x00, 0x00, + // 423 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x52, 0x31, 0x6f, 0xd3, 0x40, + 0x18, 0xf5, 0xd1, 0x52, 0x81, 0x05, 0x52, 0xe4, 0x22, 0x61, 0x65, 0xf0, 0x55, 0x1e, 0xaa, 0x0e, + 0xc4, 0x1e, 0xba, 0x75, 0x4c, 0xaa, 0x96, 0x09, 0x55, 0x1e, 0x91, 0xd0, 0xe9, 0x72, 0xfe, 0x62, + 0x9f, 0xb8, 0xf3, 0x59, 0x77, 0x6e, 0x43, 0xf8, 0x01, 0x2c, 0x2c, 0x08, 0x31, 0x30, 0xf2, 0x67, + 0x90, 0x3a, 0x76, 0x44, 0x0c, 0x16, 0x4a, 0xb6, 0x8e, 0xf9, 0x05, 0xc8, 0xe7, 0x94, 0x04, 0xf0, + 0x92, 0x4e, 0xf7, 0xdd, 0x7b, 0xef, 0x7b, 0x7a, 0x7a, 0xfa, 0xdc, 0x1e, 0x5c, 0xc9, 0xb8, 0xa4, + 0x9a, 0x4a, 0x13, 0x95, 0x5a, 0x55, 0xca, 0xf3, 0x0d, 0x70, 0x3b, 0x31, 0x25, 0x22, 0x03, 0x9c, + 0xe5, 0x94, 0x17, 0x11, 0x5c, 0xc9, 0xfe, 0xb3, 0x4c, 0x65, 0xca, 0x52, 0x71, 0x33, 0xb5, 0xfa, + 0xbe, 0x75, 0x60, 0xaa, 0x98, 0xf0, 0xac, 0x45, 0xc2, 0x8f, 0x0f, 0xdd, 0xbd, 0x0b, 0x6b, 0xe9, + 0x7d, 0x41, 0xee, 0x7e, 0xa9, 0xb9, 0xd2, 0xbc, 0x9a, 0x91, 0x42, 0x69, 0x49, 0x05, 0x7f, 0x0f, + 0xda, 0x7f, 0x70, 0x80, 0x8e, 0x1e, 0x0f, 0xd9, 0x75, 0x8d, 0x9d, 0x9f, 0x35, 0x3e, 0xcc, 0x78, + 0x95, 0x5f, 0x8e, 0x23, 0xa6, 0x1a, 0x27, 0x23, 0x95, 0x59, 0x3d, 0x03, 0x93, 0xbe, 0x8d, 0xab, + 0x59, 0x09, 0x26, 0x3a, 0x05, 0x76, 0x5b, 0xe3, 0x2e, 0xb3, 0x65, 0x8d, 0xfb, 0x33, 0x2a, 0xc5, + 0x49, 0xd8, 0x41, 0x86, 0x89, 0x77, 0x87, 0xbe, 0xfa, 0x03, 0x7a, 0x1f, 0x90, 0xdb, 0x1b, 0x53, + 0x03, 0x64, 0x02, 0x40, 0x4a, 0xd0, 0x24, 0xa3, 0xc6, 0xdf, 0xb1, 0x99, 0xde, 0x6c, 0x9d, 0xe9, + 0x3f, 0xa7, 0x65, 0x8d, 0x9f, 0xb7, 0x81, 0xfe, 0x65, 0xc2, 0xe4, 0x69, 0x03, 0x9d, 0x01, 0x5c, + 0x80, 0x3e, 0xa7, 0xc6, 0xfb, 0x8c, 0xdc, 0x7d, 0xc9, 0x0b, 0x2e, 0x2f, 0xe5, 0x5f, 0x59, 0x76, + 0xef, 0xdb, 0x4f, 0x87, 0xd9, 0xba, 0x9f, 0x0e, 0x32, 0x4c, 0x7a, 0x2b, 0x74, 0x1d, 0xea, 0x3b, + 0x72, 0x5f, 0x4c, 0x73, 0x5e, 0x81, 0xe0, 0xa6, 0x82, 0x94, 0xb0, 0x29, 0x61, 0x2a, 0x05, 0x92, + 0x53, 0x93, 0x83, 0x21, 0x13, 0xa5, 0x49, 0x0a, 0x02, 0x32, 0x5a, 0x01, 0x61, 0x54, 0x08, 0xff, + 0xd1, 0xc1, 0xce, 0xd1, 0x93, 0x61, 0x76, 0x5b, 0xe3, 0xad, 0xf6, 0x96, 0x35, 0x3e, 0x6e, 0x83, + 0x6d, 0xb3, 0x15, 0x26, 0x87, 0x1b, 0xf2, 0xd1, 0x74, 0xa4, 0x52, 0x78, 0x69, 0xb5, 0x67, 0x4a, + 0x9f, 0xae, 0x94, 0x23, 0x2a, 0xc4, 0xc9, 0xee, 0xd7, 0x6f, 0xd8, 0x19, 0x9e, 0x5f, 0xcf, 0x03, + 0x74, 0x33, 0x0f, 0xd0, 0xaf, 0x79, 0x80, 0x3e, 0x2d, 0x02, 0xe7, 0x66, 0x11, 0x38, 0x3f, 0x16, + 0x81, 0xf3, 0x7a, 0xb0, 0x51, 0xab, 0x01, 0x3e, 0xb8, 0xbb, 0x7a, 0xfb, 0xb1, 0x67, 0x1f, 0xbf, + 0x8b, 0x9b, 0xeb, 0xb6, 0x0d, 0x8f, 0xf7, 0x2c, 0x7f, 0xfc, 0x3b, 0x00, 0x00, 0xff, 0xff, 0x53, + 0xce, 0xd1, 0xa6, 0x33, 0x03, 0x00, 0x00, } func (m *Params) Marshal() (dAtA []byte, err error) { @@ -149,16 +152,6 @@ func (m *Params) MarshalToSizedBuffer(dAtA []byte) (int, error) { dAtA[i] = 0x42 } } - { - size := m.ChainId.Size() - i -= size - if _, err := m.ChainId.MarshalTo(dAtA[i:]); err != nil { - return 0, err - } - i = encodeVarintParams(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x32 { size := m.MinimumFeePerGas.Size() i -= size @@ -215,8 +208,6 @@ func (m *Params) Size() (n int) { n += 1 + l + sovParams(uint64(l)) l = m.MinimumFeePerGas.Size() n += 1 + l + sovParams(uint64(l)) - l = m.ChainId.Size() - n += 1 + l + sovParams(uint64(l)) if len(m.WhitelistedCwCodeHashesForDelegateCall) > 0 { for _, b := range m.WhitelistedCwCodeHashesForDelegateCall { l = len(b) @@ -363,40 +354,6 @@ func (m *Params) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex - case 6: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ChainId", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowParams - } - 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 ErrInvalidLengthParams - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthParams - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if err := m.ChainId.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex case 8: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field WhitelistedCwCodeHashesForDelegateCall", wireType) diff --git a/x/evm/types/params_test.go b/x/evm/types/params_test.go index 99218af7c..342e2a2e8 100644 --- a/x/evm/types/params_test.go +++ b/x/evm/types/params_test.go @@ -1,9 +1,10 @@ package types_test import ( - sdk "github.com/cosmos/cosmos-sdk/types" "testing" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/sei-protocol/sei-chain/x/evm/types" "github.com/stretchr/testify/require" ) @@ -13,7 +14,6 @@ func TestDefaultParams(t *testing.T) { PriorityNormalizer: types.DefaultPriorityNormalizer, BaseFeePerGas: types.DefaultBaseFeePerGas, MinimumFeePerGas: types.DefaultMinFeePerGas, - ChainId: types.DefaultChainID, WhitelistedCwCodeHashesForDelegateCall: types.DefaultWhitelistedCwCodeHashesForDelegateCall, }, types.DefaultParams()) @@ -38,15 +38,6 @@ func TestValidateParamsNegativeBaseFeePerGas(t *testing.T) { require.Contains(t, err.Error(), "negative base fee per gas") } -func TestValidateParamsNegativeChainID(t *testing.T) { - params := types.DefaultParams() - params.ChainId = sdk.NewInt(-1) // Set to invalid negative value - - err := params.Validate() - require.Error(t, err) - require.Contains(t, err.Error(), "negative chain ID") -} - func TestBaseFeeMinimumFee(t *testing.T) { params := types.DefaultParams() params.MinimumFeePerGas = sdk.NewDec(1) From 1d2961b5f7d5d9d90290d94b41e87cde87ba2a5b Mon Sep 17 00:00:00 2001 From: Philip Su Date: Tue, 16 Apr 2024 17:29:27 -0700 Subject: [PATCH 17/17] V4.1.9 evm devnet release (#1552) Add v4.1.9-evm-devnet upgrade --- app/upgrades.go | 1 + 1 file changed, 1 insertion(+) diff --git a/app/upgrades.go b/app/upgrades.go index 5ab0017cc..2949c0443 100644 --- a/app/upgrades.go +++ b/app/upgrades.go @@ -87,6 +87,7 @@ var upgradesList = []string{ "v4.1.6-evm-devnet", "v4.1.7-evm-devnet", "v4.1.8-evm-devnet", + "v4.1.9-evm-devnet", } // if there is an override list, use that instead, for integration tests