Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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)
mmsqe marked this conversation as resolved.
Show resolved Hide resolved
bn, err := b.BlockNumber()
if err != nil {
return &n, err
}
height := blockNum.Int64()
currentHeight := int64(bn)

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