diff --git a/CHANGELOG.md b/CHANGELOG.md index a68507f5f2..e10cb5dcb9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -51,8 +51,9 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### Bug Fixes - (rpc) [#1688](https://github.com/evmos/ethermint/pull/1688) Align filter rule for `debug_traceBlockByNumber` -* (rpc) [#1722](https://github.com/evmos/ethermint/pull/1722) Align revert response for `eth_estimateGas` and `eth_call` as Ethereum. -* (rpc) [#1720](https://github.com/evmos/ethermint/pull/1720) Fix next block fee for historical block and calculate base fee by params. +- (rpc) [#1722](https://github.com/evmos/ethermint/pull/1722) Align revert response for `eth_estimateGas` and `eth_call` as Ethereum. +- (rpc) [#1720](https://github.com/evmos/ethermint/pull/1720) Fix next block fee for historical block and calculate base fee by params. +- (rpc) [#1685](https://github.com/evmos/ethermint/pull/1685) Fix parse for websocket connID. ### Improvements diff --git a/rpc/websockets.go b/rpc/websockets.go index 81b4948009..3ed5c7d962 100644 --- a/rpc/websockets.go +++ b/rpc/websockets.go @@ -24,6 +24,7 @@ import ( "math/big" "net" "net/http" + "strconv" "sync" "github.com/cosmos/cosmos-sdk/client" @@ -225,8 +226,16 @@ func (s *websocketsServer) readLoop(wsConn *wsConn) { continue } - connID, ok := msg["id"].(float64) - if !ok { + var connID float64 + switch id := msg["id"].(type) { + case string: + connID, err = strconv.ParseFloat(id, 64) + case float64: + connID = id + default: + err = fmt.Errorf("unknown type") + } + if err != nil { s.sendErrResponse( wsConn, fmt.Errorf("invalid type for connection ID: %T", msg["id"]).Error(), diff --git a/tests/integration_tests/test_websockets.py b/tests/integration_tests/test_websockets.py index aa045a087d..db0c5218a4 100644 --- a/tests/integration_tests/test_websockets.py +++ b/tests/integration_tests/test_websockets.py @@ -1,3 +1,11 @@ +import asyncio +import json +from collections import defaultdict + +import websockets +from pystarport import ports + + def test_single_request_netversion(ethermint): ethermint.use_websocket() eth_ws = ethermint.w3.provider @@ -7,6 +15,7 @@ def test_single_request_netversion(ethermint): # net_version should be 9000 assert response["result"] == "9000", "got " + response["result"] + ", expected 9000" + # note: # batch requests still not implemented in web3.py # todo: follow https://github.com/ethereum/web3.py/issues/832, add tests when complete @@ -15,6 +24,55 @@ def test_single_request_netversion(ethermint): # todo: follow https://github.com/ethereum/web3.py/issues/1402, add tests when complete +class Client: + def __init__(self, ws): + self._ws = ws + self._subs = defaultdict(asyncio.Queue) + self._rsps = defaultdict(asyncio.Queue) + + async def receive_loop(self): + while True: + msg = json.loads(await self._ws.recv()) + if "id" in msg: + # responses + await self._rsps[msg["id"]].put(msg) + + async def recv_response(self, rpcid): + rsp = await self._rsps[rpcid].get() + del self._rsps[rpcid] + return rsp + + async def send(self, id): + await self._ws.send( + json.dumps({"id": id, "method": "web3_clientVersion", "params": []}) + ) + rsp = await self.recv_response(id) + assert "error" not in rsp + + +def test_web3_client_version(ethermint): + ethermint_ws = ethermint.copy() + ethermint_ws.use_websocket() + port = ethermint_ws.base_port(0) + url = f"ws://127.0.0.1:{ports.evmrpc_ws_port(port)}" + loop = asyncio.get_event_loop() + + async def async_test(): + async with websockets.connect(url) as ws: + c = Client(ws) + t = asyncio.create_task(c.receive_loop()) + # run send concurrently + await asyncio.gather(*[c.send(id) for id in ["0", 1, 2.0]]) + t.cancel() + try: + await t + except asyncio.CancelledError: + # allow retry + pass + + loop.run_until_complete(async_test()) + + def test_batch_request_netversion(ethermint): return