Skip to content
This repository has been archived by the owner on Apr 4, 2024. It is now read-only.

fix(rpc): align query result of future block for eth_getTransactionCount #1638

Merged
merged 12 commits into from
Jan 27, 2023
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,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 query result of future block for `eth_getTransactionCount`.
mmsqe marked this conversation as resolved.
Show resolved Hide resolved

## [v0.20.0] - 2022-12-28

Expand Down
19 changes: 16 additions & 3 deletions rpc/backend/account_info.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -187,14 +188,26 @@ 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)
Fixed Show fixed Hide fixed
Fixed Show fixed Hide fixed

Check failure

Code scanning / gosec

Potential integer overflow by integer type conversion

Potential integer overflow by integer type conversion

Check failure

Code scanning / gosec

Potential integer overflow by integer type conversion

Potential integer overflow by integer type conversion
if height > currentHeight {
return &n, sdkerrors.Wrap(
sdkerrors.ErrInvalidHeight,
"cannot query with height in the future; please provide a valid height",
)
mmsqe marked this conversation as resolved.
Show resolved Hide resolved
}
// 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 @@ -204,6 +217,6 @@ func (b *Backend) GetTransactionCount(address common.Address, blockNum rpctypes.
return nil, err
}

n := hexutil.Uint64(nonce)
n = hexutil.Uint64(nonce)
return &n, nil
}
91 changes: 66 additions & 25 deletions tests/integration_tests/test_account.py
Original file line number Diff line number Diff line change
@@ -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)