From 1a2ee06d15b66d5b88a30b4dc4ea63d8ff00a179 Mon Sep 17 00:00:00 2001 From: mmsqe Date: Fri, 27 Jan 2023 22:10:13 +0800 Subject: [PATCH] fix(rpc): align query result of future block for eth_getTransactionCount (#1638) * add future height check for get_transaction_count * add query future account test * fasten get_transaction_count test * add change doc * fix test * update nix * Update CHANGELOG.md Co-authored-by: MalteHerrmann <42640438+MalteHerrmann@users.noreply.github.com> * Update rpc/backend/account_info.go Co-authored-by: MalteHerrmann <42640438+MalteHerrmann@users.noreply.github.com> * update nix * add test for block height in future Co-authored-by: MalteHerrmann <42640438+MalteHerrmann@users.noreply.github.com> Co-authored-by: MalteHerrmann --- CHANGELOG.md | 1 + gomod2nix.toml | 37 +++++----- rpc/backend/account_info.go | 20 +++++- rpc/backend/account_info_test.go | 19 +++++- rpc/backend/node_info_test.go | 3 + tests/integration_tests/test_account.py | 91 ++++++++++++++++++------- 6 files changed, 122 insertions(+), 49 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c6a5457688..0904e251f7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -64,6 +64,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ * (rpc) [#1613](https://github.com/evmos/ethermint/pull/1613) Change the default json-rpc listen address to localhost. * (rpc) [#1611](https://github.com/evmos/ethermint/pull/1611) Add missing next fee in fee history, fix wrong oldestBlock and align earliest input as ethereum. * (proto) [#1586](https://github.com/evmos/ethermint/pull/1586) Avoid duplicate register proto type in `evm` & `feemarket` +* (rpc) [#1638](https://github.com/evmos/ethermint/pull/1638) Align results when querying `eth_getTransactionCount` for future blocks for accounts with zero and non-zero transaction counts. * (rpc) [#1639](https://github.com/evmos/ethermint/pull/1639) Align block number input behaviour for `eth_getProof` as Ethereum. ## [v0.20.0] - 2022-12-28 diff --git a/gomod2nix.toml b/gomod2nix.toml index fc5411b740..65ab566060 100644 --- a/gomod2nix.toml +++ b/gomod2nix.toml @@ -54,11 +54,11 @@ schema = 3 version = "v0.0.0-20140422174119-9fd32a8b3d3d" hash = "sha256-NDxQzO5C5M/aDz5/pjUHfZUh4VwIXovbb3irtxWCwjY=" [mod."github.com/bgentry/speakeasy"] - version = "v0.1.0" - hash = "sha256-Gt1vj6CFovLnO6wX5u2O4UfecY9V2J9WGw1ez4HMrgk=" + version = "v0.1.1-0.20220910012023-760eaf8b6816" + hash = "sha256-Tx3sPuhsoVwrCfJdIwf4ipn7pD92OQNYvpCxl1Z9Wt0=" [mod."github.com/btcsuite/btcd"] - version = "v0.22.1" - hash = "sha256-hBU+roIELcmbW2Gz7eGZzL9qNA1bakq5wNxqCgs4TKc=" + version = "v0.22.2" + hash = "sha256-TPX7GIArd+bwOdwgPnkHyptpEVGhpkqiAydsO4srOCQ=" [mod."github.com/btcsuite/btcd/btcec/v2"] version = "v2.3.2" hash = "sha256-natWs+yIAuD1UI07iZtjPilroQLfXizFn3lNOiOT83U=" @@ -96,8 +96,8 @@ schema = 3 version = "v1.0.0-beta.1" hash = "sha256-oATkuj+fM5eBn+ywO+w/tL0AFSIEkx0J3Yz+VhVe0QA=" [mod."github.com/cosmos/cosmos-sdk"] - version = "v0.46.7" - hash = "sha256-54DCF8lrnA1oUmBJlbUlWXOP5UbenRInUROn5P5I9qI=" + version = "v0.46.8" + hash = "sha256-jETbixsZq5XJ1pl1XaVJvD5jkcygBrEcHRK/L0+XI68=" [mod."github.com/cosmos/go-bip39"] version = "v1.0.0" hash = "sha256-Qm2aC2vaS8tjtMUbHmlBSagOSqbduEEDwc51qvQaBmA=" @@ -114,8 +114,8 @@ schema = 3 version = "v6.1.0" hash = "sha256-mHYCqLedcveDjfm1EiO2EMMNJqLm9u4WHwQTy1muOoc=" [mod."github.com/cosmos/ledger-cosmos-go"] - version = "v0.12.1" - hash = "sha256-9+nr+/r4MyiogddS0JcXOuriPqXP4nxln8ts+mYQRcg=" + version = "v0.12.2" + hash = "sha256-fLkveUWxn0nZzvgsY0KTU/T1TUUQ8Ap6XTYSnJs6XXo=" [mod."github.com/creachadair/taskgroup"] version = "v0.3.2" hash = "sha256-Y261IO/d9xjV0UScqHvo31broxvnKn4IQQC9Mu6jNkE=" @@ -361,8 +361,8 @@ schema = 3 version = "v2.7.0" hash = "sha256-BKqQKCsPA73FaQwYpAY+QsWFHIncrG5jgRhC2IiNmCk=" [mod."github.com/onsi/gomega"] - version = "v1.25.0" - hash = "sha256-knaJppfBzKSMD4Gsqzx22SGrti7G5UyDBYrothAqsrs=" + version = "v1.26.0" + hash = "sha256-B18jsoJHK/oE+wudT0dOsUb41s5+ZIAu/ZBzQ5djOLE=" [mod."github.com/pelletier/go-toml/v2"] version = "v2.0.6" hash = "sha256-BxAeApnn5H+OLlH3TXGvIbtC6LmbRnjwbcfT1qMZ4PE=" @@ -447,12 +447,6 @@ schema = 3 [mod."github.com/syndtr/goleveldb"] version = "v1.0.1-0.20210819022825-2ae1ddf74ef7" hash = "sha256-36a4hgVQfwtS2zhylKpQuFhrjdc/Y8pF0dxc26jcZIU=" - [mod."github.com/tendermint/btcd"] - version = "v0.1.1" - hash = "sha256-QQl2GWZaKQtd+LQrgx2unkTLI1qye57fCWwJcmCXT/0=" - [mod."github.com/tendermint/crypto"] - version = "v0.0.0-20191022145703-50d29ede1e15" - hash = "sha256-NkoZ3hKWZt5Hca49I+1g81x1m6aQGELZ/QGLdb3uHm4=" [mod."github.com/tendermint/go-amino"] version = "v0.16.0" hash = "sha256-JW4zO/0vMzf1dXLePOqaMtiLUZgNbuIseh9GV+jQlf0=" @@ -462,6 +456,9 @@ schema = 3 [mod."github.com/tendermint/tm-db"] version = "v0.6.7" hash = "sha256-hl/3RrBrpkk2zA6dmrNlIYKs1/GfqegSscDSkA5Pjlo=" + [mod."github.com/tidwall/btree"] + version = "v1.5.0" + hash = "sha256-iWll4/+ADLVse3VAHxXYLprILugX/+3u0ZIk0YlLv/Q=" [mod."github.com/tklauser/go-sysconf"] version = "v0.3.10" hash = "sha256-Zf2NsgM9+HeM949vCce4HQtSbfUiFpeiQ716yKcFyx4=" @@ -478,8 +475,8 @@ schema = 3 version = "v0.9.1" hash = "sha256-hSVmN/f/lQHFhF60o6ej78ELC0MMoqQgqIX2hHjdTXg=" [mod."github.com/zondax/ledger-go"] - version = "v0.14.0" - hash = "sha256-RozTPSNs4RerZ4DQMBcGmvREjoRtH1G69xjhccYjIOk=" + version = "v0.14.1" + hash = "sha256-iQmShSaty50yYTbYPNd4fnOyrcEG7P2fWmj+fLJQW4s=" [mod."go.etcd.io/bbolt"] version = "v1.3.6" hash = "sha256-DenVAmyN22xUiivk6fdJp4C9ZnUJXCMDUf8E0goRRV4=" @@ -523,8 +520,8 @@ schema = 3 version = "v0.0.0-20221227171554-f9683d7f8bef" hash = "sha256-vvYjJcG73odJwPUb3sZIz4MSHnzK1Jj2uo0CwZ8S8rQ=" [mod."google.golang.org/grpc"] - version = "v1.52.0" - hash = "sha256-wYJ/ysugKxz1O9u6BxECTIGFJ3sv0XmxOfM+Y0jW3KQ=" + version = "v1.52.3" + hash = "sha256-vVkuG0kKgnh62f63unpk4JDa9rIu6kk0qtnPJOiew2M=" [mod."google.golang.org/protobuf"] version = "v1.28.2-0.20220831092852-f930b1dc76e8" hash = "sha256-li5hXlXwTJ5LIZ8bVki1AZ6UFI2gXHl33JwdX1dOrtM=" diff --git a/rpc/backend/account_info.go b/rpc/backend/account_info.go index 66f1a1d24d..9c921a4c90 100644 --- a/rpc/backend/account_info.go +++ b/rpc/backend/account_info.go @@ -22,6 +22,7 @@ import ( sdkmath "cosmossdk.io/math" sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" @@ -187,14 +188,27 @@ func (b *Backend) GetBalance(address common.Address, blockNrOrHash rpctypes.Bloc // GetTransactionCount returns the number of transactions at the given address up to the given block number. func (b *Backend) GetTransactionCount(address common.Address, blockNum rpctypes.BlockNumber) (*hexutil.Uint64, error) { + n := hexutil.Uint64(0) + bn, err := b.BlockNumber() + if err != nil { + return &n, err + } + height := blockNum.Int64() + currentHeight := int64(bn) + if height > currentHeight { + return &n, sdkerrors.Wrapf( + sdkerrors.ErrInvalidHeight, + "cannot query with height in the future (current: %d, queried: %d); please provide a valid height", + currentHeight, height, + ) + } // Get nonce (sequence) from account from := sdk.AccAddress(address.Bytes()) accRet := b.clientCtx.AccountRetriever - err := accRet.EnsureExists(b.clientCtx, from) + err = accRet.EnsureExists(b.clientCtx, from) if err != nil { // account doesn't exist yet, return 0 - n := hexutil.Uint64(0) return &n, nil } @@ -204,6 +218,6 @@ func (b *Backend) GetTransactionCount(address common.Address, blockNum rpctypes. return nil, err } - n := hexutil.Uint64(nonce) + n = hexutil.Uint64(nonce) return &n, nil } diff --git a/rpc/backend/account_info_test.go b/rpc/backend/account_info_test.go index 9aa090f564..ac6d210393 100644 --- a/rpc/backend/account_info_test.go +++ b/rpc/backend/account_info_test.go @@ -9,6 +9,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" tmrpcclient "github.com/tendermint/tendermint/rpc/client" + "google.golang.org/grpc/metadata" "github.com/evmos/ethermint/rpc/backend/mocks" rpctypes "github.com/evmos/ethermint/rpc/types" @@ -359,10 +360,26 @@ func (suite *BackendTestSuite) TestGetTransactionCount() { "pass - account doesn't exist", false, rpctypes.NewBlockNumber(big.NewInt(1)), - func(addr common.Address, bn rpctypes.BlockNumber) {}, + func(addr common.Address, bn rpctypes.BlockNumber) { + var header metadata.MD + queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient) + RegisterParams(queryClient, &header, 1) + }, true, hexutil.Uint64(0), }, + { + "fail - block height is in the future", + false, + rpctypes.NewBlockNumber(big.NewInt(10000)), + func(addr common.Address, bn rpctypes.BlockNumber) { + var header metadata.MD + queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient) + RegisterParams(queryClient, &header, 1) + }, + false, + hexutil.Uint64(0), + }, // TODO: Error mocking the GetAccount call - problem with Any type //{ // "pass - returns the number of transactions at the given address up to the given block number", diff --git a/rpc/backend/node_info_test.go b/rpc/backend/node_info_test.go index fcb4a9f0c9..b5ef6bd20e 100644 --- a/rpc/backend/node_info_test.go +++ b/rpc/backend/node_info_test.go @@ -13,6 +13,7 @@ import ( ethermint "github.com/evmos/ethermint/types" "github.com/spf13/viper" tmrpcclient "github.com/tendermint/tendermint/rpc/client" + "google.golang.org/grpc/metadata" ) func (suite *BackendTestSuite) TestRPCMinGasPrice() { @@ -247,10 +248,12 @@ func (suite *BackendTestSuite) TestSetEtherbase() { { "fail - error querying for account ", func() { + var header metadata.MD client := suite.backend.clientCtx.Client.(*mocks.Client) queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient) RegisterStatus(client) RegisterValidatorAccount(queryClient, suite.acc) + RegisterParams(queryClient, &header, 1) c := sdk.NewDecCoin("aphoton", sdk.NewIntFromBigInt(big.NewInt(1))) suite.backend.cfg.SetMinGasPrices(sdk.DecCoins{c}) delAddr, _ := suite.backend.GetCoinbase() diff --git a/tests/integration_tests/test_account.py b/tests/integration_tests/test_account.py index 612307c5c7..d1af096963 100644 --- a/tests/integration_tests/test_account.py +++ b/tests/integration_tests/test_account.py @@ -1,32 +1,73 @@ import os +import pytest from eth_account import Account +from web3 import Web3 +from .network import setup_ethermint from .utils import ADDRS, w3_wait_for_new_blocks -def test_get_transaction_count(ethermint_rpc_ws, geth): - for p in [ethermint_rpc_ws, geth]: - w3 = p.w3 - blk = hex(w3.eth.block_number) - sender = ADDRS["validator"] - - # derive a new address - account_path = "m/44'/60'/0'/0/1" - mnemonic = os.getenv("COMMUNITY_MNEMONIC") - receiver = (Account.from_mnemonic(mnemonic, account_path=account_path)).address - n0 = w3.eth.get_transaction_count(receiver, blk) - # ensure transaction send in new block - w3_wait_for_new_blocks(w3, 1, sleep=0.1) - txhash = w3.eth.send_transaction( - { - "from": sender, - "to": receiver, - "value": 1000, - } - ) - receipt = w3.eth.wait_for_transaction_receipt(txhash) - assert receipt.status == 1 - [n1, n2] = [w3.eth.get_transaction_count(receiver, b) for b in [blk, "latest"]] - assert n0 == n1 - assert n0 == n2 +@pytest.fixture(scope="module") +def custom_ethermint(tmp_path_factory): + path = tmp_path_factory.mktemp("account") + yield from setup_ethermint(path, 26700, long_timeout_commit=True) + + +@pytest.fixture(scope="module", params=["ethermint", "ethermint-ws", "geth"]) +def cluster(request, custom_ethermint, geth): + """ + run on ethermint, ethermint websocket and geth + """ + provider = request.param + if provider == "ethermint": + yield custom_ethermint + elif provider == "ethermint-ws": + ethermint_ws = custom_ethermint.copy() + ethermint_ws.use_websocket() + yield ethermint_ws + elif provider == "geth": + yield geth + else: + raise NotImplementedError + + +def derive_new_address(n=1): + # derive a new address + account_path = f"m/44'/60'/0'/0/{n}" + mnemonic = os.getenv("COMMUNITY_MNEMONIC") + return (Account.from_mnemonic(mnemonic, account_path=account_path)).address + + +def test_get_transaction_count(cluster): + w3: Web3 = cluster.w3 + blk = hex(w3.eth.block_number) + sender = ADDRS["validator"] + + receiver = derive_new_address() + n0 = w3.eth.get_transaction_count(receiver, blk) + # ensure transaction send in new block + w3_wait_for_new_blocks(w3, 1, sleep=0.1) + txhash = w3.eth.send_transaction( + { + "from": sender, + "to": receiver, + "value": 1000, + } + ) + receipt = w3.eth.wait_for_transaction_receipt(txhash) + assert receipt.status == 1 + [n1, n2] = [w3.eth.get_transaction_count(receiver, b) for b in [blk, "latest"]] + assert n0 == n1 + assert n0 == n2 + + +def test_query_future_blk(cluster): + w3: Web3 = cluster.w3 + acc = derive_new_address(2) + current = w3.eth.block_number + future = current + 1000 + with pytest.raises(ValueError) as exc: + w3.eth.get_transaction_count(acc, hex(future)) + print(acc, str(exc)) + assert "-32000" in str(exc)