Skip to content

Commit

Permalink
adding RPC Post Payload to error handler
Browse files Browse the repository at this point in the history
  • Loading branch information
elicbarbieri committed Aug 29, 2024
1 parent 2ba0f85 commit 637c0c1
Show file tree
Hide file tree
Showing 6 changed files with 151 additions and 123 deletions.
25 changes: 17 additions & 8 deletions nethermind/idealis/rpc/base/async_rpc.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,28 +46,38 @@ 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

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:
Expand All @@ -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}")

Expand Down
87 changes: 48 additions & 39 deletions nethermind/idealis/rpc/ethereum/execution.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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)
Expand All @@ -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)
Expand Down Expand Up @@ -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)
122 changes: 65 additions & 57 deletions nethermind/idealis/rpc/starknet/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down Expand Up @@ -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])
Expand All @@ -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:
Expand Down Expand Up @@ -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)


Expand All @@ -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)
32 changes: 18 additions & 14 deletions nethermind/idealis/rpc/starknet/trace.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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"
)
Expand Down
4 changes: 2 additions & 2 deletions tests/starknet/parsing/test_block_parsing.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Loading

0 comments on commit 637c0c1

Please sign in to comment.