Esempio n. 1
0
    async def test_multiple_rpc_calls_mixed_response(self):
        # unlikely to ever actually happen in practice, but should be handled
        async with WsProvider(self.ws_uri) as ws:
            self.assertEqual(1, len(self.server._connections))

            connection_handler = self.server._connections[0]
            connection_handler.rpc_handler.handle_request = AsyncMock()

            subscribe_task_1 = asyncio.create_task(
                ws.call_bx(RpcRequestType.SUBSCRIBE, ["newTxs"],
                           request_id="123"))
            await asyncio.sleep(0)
            subscribe_task_2 = asyncio.create_task(
                ws.call_bx(RpcRequestType.SUBSCRIBE, ["newTxs"],
                           request_id="124"))

            server_ws = connection_handler.ws
            assert server_ws is not None

            # send responses out of order
            await server_ws.send(JsonRpcResponse("124", "subid2").to_jsons())
            await server_ws.send(JsonRpcResponse("123", "subid1").to_jsons())

            await asyncio.sleep(0.01)
            self.assertTrue(subscribe_task_1.done())
            self.assertTrue(subscribe_task_2.done())

            subscription_1 = subscribe_task_1.result()
            self.assertEqual("123", subscription_1.id)
            self.assertEqual("subid1", subscription_1.result)

            subscription_2 = subscribe_task_2.result()
            self.assertEqual("subid2", subscription_2.result)
    async def test_send_receive_messages(self):
        await self.provider.initialize()

        rpc_message = JsonRpcResponse("1", "foo")
        await self.provider.get_test_websocket().recv_messages.put(
            rpc_message.to_jsons())

        emitted_message = await self.provider.get_rpc_response("1")
        self.assertEqual(rpc_message, emitted_message)
Esempio n. 3
0
    def test_serialize_deserialize_result(self):
        rpc_response = JsonRpcResponse(
            "1", "result", None
        )

        serialized = rpc_response.to_jsons()
        deserialized = JsonRpcResponse.from_jsons(serialized)

        self.assertEqual(rpc_response.id, deserialized.id)
        self.assertEqual(rpc_response.result, deserialized.result)
        self.assertEqual(rpc_response.error, deserialized.error)
Esempio n. 4
0
def format_rpc_error(rpc_error: RpcError, status_code: int,
                     content_type: ContentType) -> Response:
    if content_type == ContentType.PLAIN:
        return web.json_response(JsonRpcResponse(rpc_error.id,
                                                 error=rpc_error).to_jsons(),
                                 status=status_code,
                                 content_type=ContentType.PLAIN.value)
    else:
        return web.json_response(
            text=JsonRpcResponse(rpc_error.id, error=rpc_error).to_jsons(),
            status=status_code,
        )
Esempio n. 5
0
    async def test_onblock_feed_default_subscribe(self):
        self.gateway_node.opts.eth_ws_uri = f"ws://{constants.LOCALHOST}:8005"
        block_height = 100
        name = "abc123"

        self.gateway_node.feed_manager.register_feed(
            EthOnBlockFeed(self.gateway_node))
        self.gateway_node.eth_ws_proxy_publisher = MockEthWsProxyPublisher(
            "", None, None, self.gateway_node)
        self.gateway_node.eth_ws_proxy_publisher.call_rpc = AsyncMock(
            return_value=JsonRpcResponse(request_id=1))

        async with WsProvider(self.ws_uri) as ws:
            subscription_id = await ws.subscribe(
                rpc_constants.ETH_ON_BLOCK_FEED_NAME,
                {"call_params": [{
                    "data": "0x",
                    "name": name
                }]},
            )

            self.gateway_node.feed_manager.publish_to_feed(
                FeedKey(rpc_constants.ETH_ON_BLOCK_FEED_NAME),
                EventNotification(block_height=block_height),
            )

            subscription_message = await ws.get_next_subscription_notification_by_id(
                subscription_id)
            self.assertEqual(subscription_id,
                             subscription_message.subscription_id)
            print(subscription_message)
            self.assertEqual(block_height,
                             subscription_message.notification["blockHeight"])

            self.assertEqual(name, subscription_message.notification["name"])
Esempio n. 6
0
    async def test_camel_case(self):
        await self.server.stop()

        self.server = WsServer(constants.LOCALHOST, 8005, self.feed_manager,
                               self.gateway_node, Case.CAMEL)
        await self.server.start()

        feed = TestFeed("foo")
        self.feed_manager.register_feed(feed)

        @dataclass
        class DataEntry:
            field_one: str

        def publish():
            feed.publish(DataEntry("123"))
            feed.publish(DataEntry("234"))

        async with websockets.connect(self.ws_uri) as ws:
            asyncio.get_event_loop().call_later(0.1, publish)
            await ws.send(
                BxJsonRpcRequest("2", RpcRequestType.SUBSCRIBE,
                                 ["foo", {}]).to_jsons())

            response = await ws.recv()
            parsed_response = JsonRpcResponse.from_jsons(response)

            self.assertEqual("2", parsed_response.id)
            self.assertIsNotNone("1", parsed_response.result)
            subscriber_id = parsed_response.result

            self._assert_notification({"fieldOne": "123"}, subscriber_id, await
                                      ws.recv())
            self._assert_notification({"fieldOne": "234"}, subscriber_id, await
                                      ws.recv())
Esempio n. 7
0
 def setUp(self) -> None:
     self._account_model = BdnAccountModelBase(
         account_id="",
         logical_account_name="",
         certificate="",
         expire_date=utils_constants.DEFAULT_EXPIRATION_DATE.isoformat(),
         cloud_api=BdnServiceModelConfigBase(
             msg_quota=None,
             permit=BdnServiceModelBase(service_type=BdnServiceType.PERMIT),
             expire_date=utils_constants.DEFAULT_EXPIRATION_DATE.isoformat(
             ),
         ),
         blockchain_protocol="Ethereum",
         blockchain_network="Mainnet",
     )
     self.rpc_port = helpers.get_free_port()
     opts = gateway_helpers.get_gateway_opts(
         8000,
         rpc_port=self.rpc_port,
         account_model=self._account_model,
         blockchain_protocol="Ethereum",
     )
     self.node = MockGatewayNode(opts)
     self.node.eth_ws_proxy_publisher = MockEthWsProxyPublisher(
         None, None, None, self.node)
     self.node.eth_ws_proxy_publisher.call_rpc = AsyncMock(
         return_value=JsonRpcResponse(request_id=1))
     self.sut = EthOnBlockFeed(self.node)
 async def call_rpc(
     self,
     method: str,
     params: Union[List[Any], Dict[Any, Any], None],
     request_id: Optional[str] = None
 ) -> JsonRpcResponse:
     return JsonRpcResponse(request_id=request_id, result={})
Esempio n. 9
0
 async def handle_request(self, websocket: WebSocketServerProtocol, _path: str) -> None:
     async for message in websocket:
         try:
             response = await self.rpc_handler.handle_request(message)
         except RpcError as err:
             response = JsonRpcResponse(err.id, error=err).to_jsons()
         await websocket.send(response)
Esempio n. 10
0
    def test_serialize_deserialize_error(self):
        rpc_response = JsonRpcResponse(
            "1", None, RpcInvalidParams("1", "bad message")
        )

        serialized = rpc_response.to_jsons()
        deserialized = JsonRpcResponse.from_jsons(serialized)

        self.assertEqual(rpc_response.id, deserialized.id)
        self.assertEqual(rpc_response.result, deserialized.result)

        self.assertNotEqual(rpc_response.error, deserialized.error)
        self.assertIsInstance(deserialized.error, RpcError)
        self.assertEqual(rpc_response.error.code, deserialized.error.code)
        self.assertEqual(rpc_response.error.message, deserialized.error.message)
        self.assertEqual(rpc_response.error.data, deserialized.error.data)
Esempio n. 11
0
    async def process_request(self) -> JsonRpcResponse:
        transaction_hash = self.transaction_hash
        assert transaction_hash is not None

        transaction_service = self.node.get_tx_service(self.get_network_num())
        transaction_key = transaction_service.get_transaction_key(
            transaction_hash)

        status = "unknown"
        short_ids = []
        assigned_time = "n/a"
        if transaction_service.has_transaction_contents_by_key(
                transaction_key):
            status = "pending short ID"

        if transaction_service.has_transaction_short_id_by_key(
                transaction_key):
            status = "assigned short ID"
            short_ids = transaction_service.get_short_ids_by_key(
                transaction_key)
            most_recent_timestamp = max([
                transaction_service.get_short_id_assign_time(short_id)
                for short_id in short_ids
            ])
            assigned_time = datetime.datetime.fromtimestamp(
                most_recent_timestamp).isoformat()

        payload = {
            "status": status,
            "short_ids": short_ids,
            "assignment_time": assigned_time
        }
        return JsonRpcResponse(self.request_id, payload)
Esempio n. 12
0
 async def process_request(self) -> JsonRpcResponse:
     feed_name = self.unsubscribe_handler(self.subscriber_id)
     if feed_name is None:
         raise RpcInvalidParams(
             self.request_id,
             f"Subscriber {self.subscriber_id} was not found.")
     self.feed_manager.unsubscribe_from_feed(feed_name, self.subscriber_id)
     return JsonRpcResponse(self.request_id, True)
Esempio n. 13
0
    async def request(self, req: BxJsonRpcRequest):
        headers = {
            rpc_constants.CONTENT_TYPE_HEADER_KEY: ContentType.JSON.value
        }

        async with ClientSession() as session:
            async with session.post(self.rpc_url,
                                    data=req.to_jsons(),
                                    headers=headers) as response:
                return JsonRpcResponse.from_json(await response.json())
Esempio n. 14
0
 async def consumer(ws, _path):
     try:
         async for message in ws:
             rpc_request = JsonRpcRequest.from_jsons(message)
             if rpc_request.method_name == "eth_subscribe":
                 await ws.send(
                     JsonRpcResponse(rpc_request.id, self.eth_subscription_id).to_jsons()
                 )
             elif rpc_request.method_name == "eth_getTransactionByHash":
                 nonce = int(rpc_request.id)
                 await ws.send(
                     JsonRpcResponse(
                         rpc_request.id,
                         tx_to_eth_rpc_json(self.sample_transactions[nonce])
                     ).to_jsons()
                 )
     except Exception as e:
         # server closed, exit
         pass
    async def process_request(self) -> JsonRpcResponse:
        params = self.params
        assert isinstance(params, list)

        subscriber = self.feed_manager.subscribe_to_feed(
            self.feed_key, self.options)
        assert subscriber is not None  # already validated
        self.subscribe_handler(subscriber, self.feed_key)

        return JsonRpcResponse(self.request_id, subscriber.subscription_id)
Esempio n. 16
0
    async def test_subscribe_and_unsubscribe(self):
        feed = TestFeed("foo")
        self.feed_manager.register_feed(feed)

        def publish():
            feed.publish(1)
            feed.publish(2)
            feed.publish(3)

        async with websockets.unix_connect(self.ipc_path) as ws:
            asyncio.get_event_loop().call_later(
                0.1, publish
            )
            await ws.send(
                BxJsonRpcRequest(
                    "2", RpcRequestType.SUBSCRIBE, ["foo", {}]
                ).to_jsons()
            )
            response = await ws.recv()
            parsed_response = JsonRpcResponse.from_jsons(response)

            self.assertEqual("2", parsed_response.id)
            self.assertIsNotNone("1", parsed_response.result)
            subscriber_id = parsed_response.result

            self._assert_notification(1, subscriber_id, await ws.recv())
            self._assert_notification(2, subscriber_id, await ws.recv())
            self._assert_notification(3, subscriber_id, await ws.recv())

            await ws.send(
                BxJsonRpcRequest(
                    "3", RpcRequestType.UNSUBSCRIBE, [subscriber_id]
                ).to_jsons()
            )
            response = await ws.recv()
            parsed_response = JsonRpcResponse.from_jsons(response)
            self.assertEqual("3", parsed_response.id)
            self.assertTrue(parsed_response.result)

            publish()
            with self.assertRaises(TimeoutError):
                await asyncio.wait_for(ws.recv(), 0.1)
Esempio n. 17
0
 async def handle_request(self, request: Request) -> None:
     websocket = self.ws
     await websocket.prepare(request)
     async for message in websocket:
         try:
             response = await self.ws_rpc_handler.handle_request(
                 # pyre-ignore[6] Expected `multidict.CIMultiDictProxy[typing.Any]`
                 WsRequest(cast(WSMessage, message), request.headers))
         except RpcError as err:
             response = JsonRpcResponse(err.id, error=err).to_jsons()
         await websocket.send_str(response)
Esempio n. 18
0
    async def test_eth_transaction_receipts_feed_specify_include(self):
        self.gateway_node.opts.eth_ws_uri = f"ws://{constants.LOCALHOST}:8005"
        self.gateway_node.feed_manager.register_feed(
            EthTransactionReceiptsFeed(self.gateway_node, 0))
        self.gateway_node.eth_ws_proxy_publisher = MockEthWsProxyPublisher(
            "", None, None, self.gateway_node)
        receipt_response = {
            "blockHash":
            "0xe6f67c6948158c45dct10b169ad6bf3a96c6402489733a03051feaf7d09e7b54",
            "blockNumber": "0xaf25e5",
            "cumulativeGasUsed": "0xbdb9ae",
            "from": "0x82170dd1cec50107963bf1ba1e80955ea302c5ce",
            "gasUsed": "0x5208",
            "logs": [],
            "logsBloom":
            "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
            "status": "0x1",
            "to": "0xa09f63d9a0b0fbe89e41e51282ad660e7c876165",
            "transactionHash":
            "0xbcdc5b22bf463f9b8766dd61cc133caf13472b6ae8474061134d9dc2983625f6",
            "transactionIndex": "0x90"
        }
        receipt_result = {
            "transactionHash":
            "0xbcdc5b22bf463f9b8766dd61cc133caf13472b6ae8474061134d9dc2983625f6"
        }
        self.gateway_node.eth_ws_proxy_publisher.call_rpc = AsyncMock(
            return_value=JsonRpcResponse(request_id=1,
                                         result=receipt_response))
        block = mock_eth_messages.get_dummy_block(5)
        internal_block_info = InternalEthBlockInfo.from_new_block_msg(
            NewBlockEthProtocolMessage(None, block, 1))
        eth_raw_block = EthRawBlock(
            1, internal_block_info.block_hash(), FeedSource.BLOCKCHAIN_RPC,
            get_block_message_lazy(internal_block_info))

        async with WsProvider(self.ws_uri) as ws:
            subscription_id = await ws.subscribe(
                rpc_constants.ETH_TRANSACTION_RECEIPTS_FEED_NAME,
                {"include": ["receipt.transaction_hash"]})

            self.gateway_node.feed_manager.publish_to_feed(
                FeedKey(rpc_constants.ETH_TRANSACTION_RECEIPTS_FEED_NAME),
                eth_raw_block)

            for i in range(len(block.transactions)):
                subscription_message = await ws.get_next_subscription_notification_by_id(
                    subscription_id)
                self.assertEqual(subscription_id,
                                 subscription_message.subscription_id)
                self.assertEqual(subscription_message.notification,
                                 {"receipt": receipt_result})
Esempio n. 19
0
    async def test_subscribe_and_unsubscribe(self):
        self.gateway_node.account_model.get_feed_service_config_by_name = MagicMock(
            return_value=self.gateway_node.account_model.
            new_transaction_streaming)
        feed = TestFeed("foo")
        self.feed_manager.register_feed(feed)

        def publish():
            feed.publish(1)
            feed.publish(2)
            feed.publish(3)

        async with websockets.connect(self.ws_uri) as ws:
            asyncio.get_event_loop().call_later(0.1, publish)
            await ws.send(
                BxJsonRpcRequest("2", RpcRequestType.SUBSCRIBE,
                                 ["foo", {}]).to_jsons())
            response = await ws.recv()
            parsed_response = JsonRpcResponse.from_jsons(response)

            self.assertEqual("2", parsed_response.id)
            self.assertIsNotNone("1", parsed_response.result)
            subscriber_id = parsed_response.result

            self._assert_notification(1, subscriber_id, await ws.recv())
            self._assert_notification(2, subscriber_id, await ws.recv())
            self._assert_notification(3, subscriber_id, await ws.recv())

            await ws.send(
                BxJsonRpcRequest("3", RpcRequestType.UNSUBSCRIBE,
                                 [subscriber_id]).to_jsons())
            response = await ws.recv()
            parsed_response = JsonRpcResponse.from_jsons(response)
            self.assertEqual("3", parsed_response.id)
            self.assertTrue(parsed_response.result)

            publish()
            with self.assertRaises(TimeoutError):
                await asyncio.wait_for(ws.recv(), 0.1)
    async def request(self, req: BxJsonRpcRequest):
        headers = dict()
        headers[rpc_constants.CONTENT_TYPE_HEADER_KEY] = rpc_constants.PLAIN_HEADER_TYPE
        headers[rpc_constants.AUTHORIZATION_HEADER_KEY] = base64.b64encode(
                f"{self.rpc_user}:{self.rpc_password}".encode("utf-8")
            ).decode("utf-8")

        async with ClientSession() as session:
            async with session.post(
                self.rpc_url,
                data=req.to_jsons(),
                headers=headers
            ) as response:
                return JsonRpcResponse.from_jsons(await response.json())
Esempio n. 21
0
    async def request(self, req: BxJsonRpcRequest):
        headers = {
            rpc_constants.CONTENT_TYPE_HEADER_KEY:
            ContentType.JSON.value,
            rpc_constants.AUTHORIZATION_HEADER_KEY:
            base64.b64encode(f"{self.rpc_user}:{self.rpc_password}".encode(
                "utf-8")).decode("utf-8")
        }

        async with ClientSession() as session:
            async with session.post(self.rpc_url,
                                    data=req.to_jsons(),
                                    headers=headers) as response:
                return JsonRpcResponse.from_json(await response.json())
    async def process_transaction(self, network_num: int, account_id: str,
                                  transaction_str: str) -> JsonRpcResponse:

        if self.synchronous:
            return await self.post_process_transaction(network_num, account_id,
                                                       self.track_flag,
                                                       transaction_str)
        else:
            asyncio.create_task(
                self.post_process_transaction(network_num, account_id,
                                              self.track_flag,
                                              transaction_str))
        return JsonRpcResponse(self.request_id, {
            "tx_hash": "not available with async",
        })
Esempio n. 23
0
 async def test_blxr_eth_call(self):
     self.gateway_node.eth_ws_proxy_publisher = MockEthWsProxyPublisher(
         None, None, None, None)
     self.gateway_node.eth_ws_proxy_publisher.call_rpc = AsyncMock(
         return_value=JsonRpcResponse(request_id=1))
     result = await self.request(
         BxJsonRpcRequest(
             "1", RpcRequestType.BLXR_ETH_CALL, {
                 rpc_constants.TRANSACTION_JSON_PARAMS_KEY:
                 TRANSACTION_JSON,
                 rpc_constants.TAG_PARAMS_KEY: "latest"
             }))
     self.gateway_node.eth_ws_proxy_publisher.call_rpc.mock.assert_called_with(
         "eth_call", [TRANSACTION_JSON, "latest"])
     self.assertIsNone(result.error)
    async def test_disconnect_after_startup_retry(self):
        gateway_constants.WS_MIN_RECONNECT_TIMEOUT_S = 10

        self.provider.retry_connection = True
        await self.provider.initialize()

        await self.provider.ws.close()
        await asyncio.sleep(0)

        self.assertTrue(self.provider.running)
        self.assertFalse(self.provider.connected_event.is_set())

        rpc_message = JsonRpcResponse("1", "foo")
        await self.provider.get_test_websocket().recv_messages.put(
            rpc_message.to_jsons())
        with self.assertRaises(WsException):
            await self.provider.get_rpc_response("1")

        send_task = asyncio.create_task(
            self.provider.call(JsonRpcRequest("2", "123", None)))
        await asyncio.sleep(0.1)
        self.assertFalse(send_task.done())
        self.assertEqual(0,
                         len(self.provider.get_test_websocket().send_messages))

        # reconnect now
        await self.provider.connect()
        await asyncio.sleep(0)

        # re-emit new message
        await self.provider.get_test_websocket().recv_messages.put(
            rpc_message.to_jsons())
        received_message = await self.provider.get_rpc_response("1")
        self.assertEqual(rpc_message, received_message)

        # still waiting for response
        self.assertFalse(send_task.done())
        self.assertEqual(1,
                         len(self.provider.get_test_websocket().send_messages))

        # task finished
        response_rpc_message = JsonRpcResponse("2", "foo")
        await self.provider.get_test_websocket().recv_messages.put(
            response_rpc_message.to_jsons())
        await asyncio.sleep(0.01)
        self.assertTrue(send_task.done())
        self.assertEqual(response_rpc_message, send_task.result())
Esempio n. 25
0
    async def receive(self) -> None:
        # TODO: preferably this would be an infinite loop that waits on
        # self.connected_event.wait(), but it seems that `async for` never
        # throws an exception, even when the websocket gets disconnected.

        logger.trace("Started receiving on websocket.")
        ws = self.ws
        assert ws is not None

        async for next_message in ws:
            logger.trace("Received message on websocket: {}", next_message)

            # process response messages
            # noinspection PyBroadException
            try:
                response_message = JsonRpcResponse.from_jsons(next_message)
            # pylint: disable=broad-except
            except Exception:
                pass
            else:
                await self.response_messages.put(response_message)
                continue

            # process notification messages
            try:
                subscription_message = JsonRpcRequest.from_jsons(next_message)
                params = subscription_message.params
                assert isinstance(params, dict)
                await self.subscription_manager.receive_message(
                    SubscriptionNotification(
                        params["subscription"],
                        params["result"],
                    ))
            # pylint: disable=broad-except
            except Exception as e:
                logger.warning(log_messages.ETH_RPC_PROCESSING_ERROR,
                               next_message,
                               e,
                               exc_info=True)

        logger.trace(
            "Temporarily stopped receiving message on websocket. Awaiting reconnection."
        )
Esempio n. 26
0
 async def handle_get_request(self, request: Request) -> Response:
     try:
         self.authenticate_request(request)
     except HTTPUnauthorized as e:
         return format_http_error(e, self._handler.content_type)
     else:
         response_dict = {
             "result": {
                 "required_request_type":
                 "POST",
                 "required_headers": [{
                     rpc_constants.CONTENT_TYPE_HEADER_KEY:
                     ContentType.PLAIN.value
                 }],
                 "payload_structures":
                 await self._handler.help(),
             }
         }
         json_response = JsonRpcResponse.from_json(response_dict)
         return web.json_response(json_response.to_jsons(),
                                  dumps=json_encoder.to_json)
Esempio n. 27
0
    async def process_transaction(
        self, network_num: int, account_id: str, quota_type: QuotaType, transaction_str: str
    ) -> JsonRpcResponse:

        if self.synchronous:
            return await self.post_process_transaction(
                network_num, account_id, quota_type, transaction_str
            )
        else:
            asyncio.create_task(
                self.post_process_transaction(
                    network_num, account_id, quota_type, transaction_str
                )
            )
        return JsonRpcResponse(
            self.request_id,
            {
                "tx_hash": "not available with async",
                "quota_type": quota_type.name.lower(),
                "synchronous": str(self.synchronous)
            }
        )
Esempio n. 28
0
    def test_serialize_to_camelCase(self):
        result = {
            "field_name": "foo",
            "otherFieldName": "bar",
            "nested_field": {
                "nested_field_name": "baz"
            }
        }
        rpc_response = JsonRpcResponse("1", result, None)
        json_serialized = rpc_response.to_json(Case.CAMEL)
        self.assertEqual("foo", json_serialized["result"]["fieldName"])
        self.assertEqual("bar", json_serialized["result"]["otherFieldName"])
        self.assertEqual("baz", json_serialized["result"]["nestedField"]["nestedFieldName"])

        simple_rpc_response = JsonRpcResponse("1", "foo", None)
        simple_json = simple_rpc_response.to_json(Case.CAMEL)
        self.assertEqual("foo", simple_json["result"])
Esempio n. 29
0
 def test_serialize_error_rpc_notification(self):
     rpc_notification = JsonRpcRequest(None, "sub", ["subid", {}])
     with self.assertRaises(ValueError):
         JsonRpcResponse.from_json(rpc_notification.to_json())
Esempio n. 30
0
 async def request(self, req: BxJsonRpcRequest) -> JsonRpcResponse:
     async with websockets.unix_connect(self.ipc_path) as ws:
         await ws.send(req.to_jsons())
         return JsonRpcResponse.from_jsons(await ws.recv())