From 637c0c1db048a7e9bf83523c0a3f1f9cd25db054 Mon Sep 17 00:00:00 2001 From: Eli Barbieri Date: Thu, 29 Aug 2024 11:50:42 -0700 Subject: [PATCH] adding RPC Post Payload to error handler --- nethermind/idealis/rpc/base/async_rpc.py | 25 ++-- nethermind/idealis/rpc/ethereum/execution.py | 87 +++++++------ nethermind/idealis/rpc/starknet/core.py | 122 ++++++++++--------- nethermind/idealis/rpc/starknet/trace.py | 32 ++--- tests/starknet/parsing/test_block_parsing.py | 4 +- tests/starknet/rpc/test_events.py | 4 +- 6 files changed, 151 insertions(+), 123 deletions(-) diff --git a/nethermind/idealis/rpc/base/async_rpc.py b/nethermind/idealis/rpc/base/async_rpc.py index efe6761..77070f8 100644 --- a/nethermind/idealis/rpc/base/async_rpc.py +++ b/nethermind/idealis/rpc/base/async_rpc.py @@ -46,8 +46,16 @@ def create_aiohttp_session( async def parse_async_rpc_response( + payload: dict[str, Any], response: ClientResponse, ) -> Any: + """ + Parse an async RPC response and return the result. + + :param payload: RPC Request JSON + :param response: AioHttp Response Object + :return: response.json()['result'] if successful, and raises a formatted exception if not + """ try: response_json = await response.json() # Async read response bytes response.release() # Release the connection back to the pool, keeping TCP conn alive @@ -55,19 +63,21 @@ async def parse_async_rpc_response( try: return_json = response_json["result"] if return_json is None: - raise RPCError(f"RPC Returned Empty JSON for Request {response.request_info}") + raise RPCError( + f"RPC Returned Empty JSON for Request {payload}... Request Info: {response.request_info}" + ) return return_json except KeyError: if "error" in response_json.keys(): - raise RPCError(f"Error in RPC response: {response_json['error']}") + raise RPCError(f"Error in RPC response: {response_json['error']}. Request Payload: {payload}") if "message" in response_json.keys(): if "rate limit" in response_json["message"] or "rate-limit" in response_json["message"]: raise RPCRateLimitError(f"Rate Limits Exceeded for RPC {response.url}") - raise RPCError(f"Error for RPC {response.url} -- Response: {response_json}") + raise RPCError(f"Error for RPC {response.url} -- Response: {response_json} -- Request Payload: {payload}") except ContentTypeError: match response.status: @@ -77,12 +87,11 @@ async def parse_async_rpc_response( raise RPCHostError("Internal Server Error") case _: - logger.error(f"\n{'-' * 40}") - logger.error("Unexpected Error in response for request: ", response.request_info) - logger.error(f"Error Code: {response.status}") - logger.error(await response.text()) - logger.error("-" * 40) + logger.error(f"Unexpected Error in response for request: {payload}") + logger.error(f"Response Information: {response.request_info}") + logger.error(f"Error Code: {response.status} -- Response Text: {await response.text()}") raise RPCError("Unexpected Content Type AioHttp Error") + except TimeoutError: raise RPCTimeoutError(f"Timeout Error for RPC Host {response.host}") diff --git a/nethermind/idealis/rpc/ethereum/execution.py b/nethermind/idealis/rpc/ethereum/execution.py index 2da5f75..16e7fca 100644 --- a/nethermind/idealis/rpc/ethereum/execution.py +++ b/nethermind/idealis/rpc/ethereum/execution.py @@ -54,14 +54,16 @@ async def get_blocks( async def _get_block(num: int) -> tuple[Block, list[Transaction]]: async with aiohttp_session.post( url=rpc_url, - json={ - "id": 1, - "jsonrpc": "2.0", - "method": "eth_getBlockByNumber", - "params": [hex(num), full_transactions], - }, + json=( + payload := { + "id": 1, + "jsonrpc": "2.0", + "method": "eth_getBlockByNumber", + "params": [hex(num), full_transactions], + } + ), ) as response: - block_json = await parse_async_rpc_response(response) + block_json = await parse_async_rpc_response(payload, response) logger.debug(f"Async POST -- get {len(blocks)} blocks returned {response.content_length} bytes") return parse_get_block_response(block_json) @@ -83,14 +85,16 @@ async def trace_block( async with aiohttp_session.post( url=rpc_url, - json={ - "id": 1, - "jsonrpc": "2.0", - "method": "trace_block", - "params": [block_number], - }, + json=( + payload := { + "id": 1, + "jsonrpc": "2.0", + "method": "trace_block", + "params": [block_number], + } + ), ) as response: - block_traces = await parse_async_rpc_response(response) + block_traces = await parse_async_rpc_response(payload, response) logger.debug(f"Async POST -- trace_block {block_number} returned {response.content_length} bytes") return unpack_trace_block_response(block_traces) @@ -105,14 +109,16 @@ async def debug_trace_block( async with aiohttp_session.post( url=rpc_url, - json={ - "id": 1, - "jsonrpc": "2.0", - "method": "debug_traceBlockByNumber", - "params": [block_number], - }, + json=( + payload := { + "id": 1, + "jsonrpc": "2.0", + "method": "debug_traceBlockByNumber", + "params": [block_number], + } + ), ) as response: - block_traces = await parse_async_rpc_response(response) + block_traces = await parse_async_rpc_response(payload, response) logger.debug(f"Finished Reading HTTP Response Bytes & Decoding JSON for Block {block_number} Debug Traces") return unpack_debug_trace_block_response(block_traces, block_number) @@ -140,24 +146,27 @@ async def get_events_for_contract( """ async with aiohttp_session.post( rpc_url, - json={ - "jsonrpc": "2.0", - "method": "eth_getLogs", - "params": [ - { - "address": to_hex(contract_address, pad=20) - if isinstance(contract_address, bytes) - else [to_hex(addr, pad=20) for addr in contract_address], - "fromBlock": hex(from_block) if isinstance(from_block, int) else from_block, - "toBlock": hex(to_block - 1) if isinstance(to_block, int) else to_block, - "topics": [ - to_hex(topic) if isinstance(topic, bytes) else [to_hex(t) for t in topic] for topic in topics - ], - } - ], - "id": 1, - }, + json=( + payload := { + "jsonrpc": "2.0", + "method": "eth_getLogs", + "params": [ + { + "address": to_hex(contract_address, pad=20) + if isinstance(contract_address, bytes) + else [to_hex(addr, pad=20) for addr in contract_address], + "fromBlock": hex(from_block) if isinstance(from_block, int) else from_block, + "toBlock": hex(to_block - 1) if isinstance(to_block, int) else to_block, + "topics": [ + to_hex(topic) if isinstance(topic, bytes) else [to_hex(t) for t in topic] + for topic in topics + ], + } + ], + "id": 1, + } + ), ) as events_response: - events_json = await parse_async_rpc_response(events_response) + events_json = await parse_async_rpc_response(payload, events_response) return parse_get_logs_response(events_json) diff --git a/nethermind/idealis/rpc/starknet/core.py b/nethermind/idealis/rpc/starknet/core.py index 5d15b9b..db8c727 100644 --- a/nethermind/idealis/rpc/starknet/core.py +++ b/nethermind/idealis/rpc/starknet/core.py @@ -43,14 +43,16 @@ def _starknet_block_id(block_id: int | str | bytes) -> str | dict[str, str | int async def get_current_block(aiohttp_session: ClientSession, json_rpc: str) -> int: async with aiohttp_session.post( json_rpc, - json={ - "jsonrpc": "2.0", - "method": "starknet_blockNumber", - "params": {}, - "id": 1, - }, + json=( + payload := { + "jsonrpc": "2.0", + "method": "starknet_blockNumber", + "params": {}, + "id": 1, + } + ), ) as latest_block_resp: - response_json = await parse_async_rpc_response(latest_block_resp) + response_json = await parse_async_rpc_response(payload, latest_block_resp) return int(response_json) @@ -81,14 +83,16 @@ async def get_blocks(blocks: list[int], rpc_url: str, aiohttp_session: ClientSes async def _get_block(block_number: int) -> BlockResponse: async with aiohttp_session.post( rpc_url, - json={ - "jsonrpc": "2.0", - "method": "starknet_getBlockWithTxHashes", - "params": {"block_id": _starknet_block_id(block_number)}, - "id": 1, - }, + json=( + payload := { + "jsonrpc": "2.0", + "method": "starknet_getBlockWithTxHashes", + "params": {"block_id": _starknet_block_id(block_number)}, + "id": 1, + } + ), ) as block_response: - block_json = await parse_async_rpc_response(block_response) + block_json = await parse_async_rpc_response(payload, block_response) return parse_block(block_json) response_data = await asyncio.gather(*[_get_block(block) for block in blocks]) @@ -105,17 +109,17 @@ async def _get_block( ) -> tuple[BlockResponse, list[TransactionResponse], list[Event]]: async with aiohttp_session.post( rpc_url, - json={ - "jsonrpc": "2.0", - "method": "starknet_getBlockWithReceipts", - "params": {"block_id": _starknet_block_id(block_number)}, - "id": 1, - }, - ) as block_response: - block_json = await parse_async_rpc_response(block_response) - logger.debug( - f"get_blocks_with_txns -> {block_number} returned {block_response.content.total_bytes} json bytes" - ) + json=( + payload := { + "jsonrpc": "2.0", + "method": "starknet_getBlockWithReceipts", + "params": {"block_id": _starknet_block_id(block_number)}, + "id": 1, + } + ), + ) as response: + block_json = await parse_async_rpc_response(payload, response) + logger.debug(f"get_blocks_with_txns -> {block_number} returned {response.content.total_bytes} json bytes") try: return parse_block_with_tx_receipts(block_json) except BaseException as e: @@ -208,17 +212,19 @@ async def get_contract_impl_class( """ async with aiohttp_session.post( rpc_url, - json={ - "jsonrpc": "2.0", - "method": "starknet_getClassHashAt", - "params": { - "block_id": _starknet_block_id(block_id), - "contract_address": to_hex(contract_address), - }, - "id": 1, - }, - ) as contract_response: - contract_json = await parse_async_rpc_response(contract_response) + json=( + payload := { + "jsonrpc": "2.0", + "method": "starknet_getClassHashAt", + "params": { + "block_id": _starknet_block_id(block_id), + "contract_address": to_hex(contract_address), + }, + "id": 1, + } + ), + ) as response: + contract_json = await parse_async_rpc_response(payload, response) return to_bytes(contract_json["class_hash"], pad=32) @@ -233,25 +239,27 @@ async def get_events_for_contract( ) -> list[Event]: async with aiohttp_session.post( rpc_url, - json={ - "jsonrpc": "2.0", - "method": "starknet_getEvents", - "params": { - "filter": { - "from_block": _starknet_block_id(from_block), - "to_block": _starknet_block_id(to_block), - "address": to_hex(contract_address, pad=32), - "keys": [ - [to_hex(key, pad=32) for key in event_keys] # Key[0] searches event_selector... - # Additional keys can search through indexed event keys? - # TODO: Test & implement - ], - "continuation_token": f"{from_block}-0", - "chunk_size": page_size, # Max chunk size - } - }, - "id": 1, - }, - ) as events_response: - events_json = await parse_async_rpc_response(events_response) + json=( + payload := { + "jsonrpc": "2.0", + "method": "starknet_getEvents", + "params": { + "filter": { + "from_block": _starknet_block_id(from_block), + "to_block": _starknet_block_id(to_block), + "address": to_hex(contract_address, pad=32), + "keys": [ + [to_hex(key, pad=32) for key in event_keys] # Key[0] searches event_selector... + # Additional keys can search through indexed event keys? + # TODO: Test & implement + ], + "continuation_token": f"{from_block}-0", + "chunk_size": page_size, # Max chunk size + } + }, + "id": 1, + } + ), + ) as response: + events_json = await parse_async_rpc_response(payload, response) return parse_event_response(events_json) diff --git a/nethermind/idealis/rpc/starknet/trace.py b/nethermind/idealis/rpc/starknet/trace.py index e0e2b62..6dda3b5 100644 --- a/nethermind/idealis/rpc/starknet/trace.py +++ b/nethermind/idealis/rpc/starknet/trace.py @@ -27,14 +27,16 @@ async def trace_blocks( async def _trace_block(block_number: int): async with aiohttp_session.post( url=rpc_url, - json={ - "id": 1, - "jsonrpc": "2.0", - "method": "starknet_traceBlockTransactions", - "params": {"block_id": {"block_number": block_number}}, - }, + json=( + payload := { + "id": 1, + "jsonrpc": "2.0", + "method": "starknet_traceBlockTransactions", + "params": {"block_id": {"block_number": block_number}}, + } + ), ) as response: - block_traces = await parse_async_rpc_response(response) + block_traces = await parse_async_rpc_response(payload, response) logger.debug(f"trace_blocks -> {block_number} returned {response.content.total_bytes} json bytes") try: return unpack_trace_block_response(block_traces, block_number) @@ -58,14 +60,16 @@ async def trace_transaction( ) -> ParsedTransactionTrace: async with aiohttp_session.post( url=rpc_url, - json={ - "id": 1, - "jsonrpc": "2.0", - "method": "starknet_traceTransaction", - "params": {"transaction_hash": to_hex(transaction_hash, pad=32)}, - }, + json=( + payload := { + "id": 1, + "jsonrpc": "2.0", + "method": "starknet_traceTransaction", + "params": {"transaction_hash": to_hex(transaction_hash, pad=32)}, + } + ), ) as response: - tx_trace = await parse_async_rpc_response(response) + tx_trace = await parse_async_rpc_response(payload, response) logger.debug( f"trace_transaction -> {pprint_hash(transaction_hash)} returned {response.content.total_bytes} json bytes" ) diff --git a/tests/starknet/parsing/test_block_parsing.py b/tests/starknet/parsing/test_block_parsing.py index fede384..66ef598 100644 --- a/tests/starknet/parsing/test_block_parsing.py +++ b/tests/starknet/parsing/test_block_parsing.py @@ -19,10 +19,10 @@ def test_parsing_v0_13_1_block_response(): assert len(events) == 1925 - assert events[0].tx_index == 0 + assert events[0].transaction_index == 0 assert events[0].contract_address == to_bytes("0x59a943ca214c10234b9a3b61c558ac20c005127d183b86a99a8f3c60a08b4ff") assert events[0].event_index == 0 - assert events[-1].tx_index == 190 + assert events[-1].transaction_index == 190 assert events[-1].contract_address == to_bytes("0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7") assert events[-1].event_index == 9 diff --git a/tests/starknet/rpc/test_events.py b/tests/starknet/rpc/test_events.py index 9a648e0..a6d9a57 100644 --- a/tests/starknet/rpc/test_events.py +++ b/tests/starknet/rpc/test_events.py @@ -16,11 +16,9 @@ async def test_get_starknet_eth_transfers(starknet_rpc_url, async_http_session): aiohttp_session=async_http_session, ) - print(events) - for e in events: # There is no way to know tx & event index when querying events by contract - assert e.tx_index == -1 # Unknown + assert e.transaction_index == -1 # Unknown assert e.event_index == -1 # Unknown assert e.contract_address == to_bytes("049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7")