Skip to content

Commit

Permalink
fix(rpc): align query result of future block for eth_getTransactionCo…
Browse files Browse the repository at this point in the history
…unt (evmos#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 <[email protected]>

* Update rpc/backend/account_info.go

Co-authored-by: MalteHerrmann <[email protected]>

* update nix

* add test for block height in future

Co-authored-by: MalteHerrmann <[email protected]>
Co-authored-by: MalteHerrmann <[email protected]>
  • Loading branch information
3 people committed Mar 14, 2023
1 parent 58a3ffe commit ebe08c7
Show file tree
Hide file tree
Showing 4 changed files with 109 additions and 30 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ Ref: https://keepachangelog.com/en/1.0.0/

* (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.
* (rpc) [#1613](https://github.com/evmos/ethermint/pull/1613) Change the default json-rpc listen address to localhost.
* (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) [#1688](https://github.com/evmos/ethermint/pull/1688) Align filter rule for `debug_traceBlockByNumber`

### Improvements
Expand Down
20 changes: 17 additions & 3 deletions rpc/backend/account_info.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,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"
Expand Down Expand Up @@ -172,14 +173,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
}

Expand All @@ -189,6 +203,6 @@ func (b *Backend) GetTransactionCount(address common.Address, blockNum rpctypes.
return nil, err
}

n := hexutil.Uint64(nonce)
n = hexutil.Uint64(nonce)
return &n, nil
}
19 changes: 18 additions & 1 deletion rpc/backend/account_info_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -347,10 +348,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),
},
}
for _, tc := range testCases {
suite.Run(fmt.Sprintf("Case %s", tc.name), func() {
Expand Down
99 changes: 73 additions & 26 deletions tests/integration_tests/test_account.py
Original file line number Diff line number Diff line change
@@ -1,26 +1,73 @@
from .utils import ADDRS, derive_new_account, 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
receiver = derive_new_account().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
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


@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)

0 comments on commit ebe08c7

Please sign in to comment.