From 8f7b5dfc4eb73a324efd4ac65a9526cad5016342 Mon Sep 17 00:00:00 2001 From: BobTheBuidler <70677534+BobTheBuidler@users.noreply.github.com> Date: Wed, 10 Jan 2024 02:32:37 -0500 Subject: [PATCH] chore: cleanup logging of missing trie node errs (#121) --- dank_mids/constants.py | 2 +- dank_mids/requests.py | 34 ++++++++++++++++++++++++++++------ 2 files changed, 29 insertions(+), 7 deletions(-) diff --git a/dank_mids/constants.py b/dank_mids/constants.py index f9860719..06dc3f31 100644 --- a/dank_mids/constants.py +++ b/dank_mids/constants.py @@ -4,7 +4,7 @@ from multicall.constants import Network TOO_MUCH_DATA_ERRS = ["Payload Too Large", "content length too large", "request entity too large", "batch limit exceeded"] -RETRY_ERRS = ["connection reset by peer", "server disconnected", "execution aborted (timeout = 5s)", "batch limit exceeded"] +RETRY_ERRS = ["connection reset by peer", "server disconnected", "execution aborted (timeout =", "batch limit exceeded"] GAS_LIMIT = multicall.constants.GAS_LIMIT MULTICALL2_OVERRIDE_CODE = multicall.constants.MULTICALL2_BYTECODE diff --git a/dank_mids/requests.py b/dank_mids/requests.py index 9d78131e..d3920274 100644 --- a/dank_mids/requests.py +++ b/dank_mids/requests.py @@ -275,8 +275,26 @@ async def create_duplicate(self) -> Self: # Not actually self, but for typing pu await self.semaphore.acquire() return retval + +INDIVIDUAL_CALL_REVERT_STRINGS = { + "invalid opcode", + "missing trie node", + "resource not found", + "invalid ether transfer", + "error processing call revert", +} + revert_threads = PruningThreadPoolExecutor(4) +def _is_call_revert(e: BadResponse) -> bool: + """Returns True if a particular `BadResponse` for a multicall was caused by a failure in one of the individual calls it contained, False for any other reason""" + stre = f"{e}" + return any(s in stre for s in INDIVIDUAL_CALL_REVERT_STRINGS) + +def _needs_full_request_spec(e: BadResponse): + """Returns True if this particular `BadResponse` indicates that the node we are using requires the full request spec. Dank mids will detect this and changeover automagically.""" + + class eth_call(RPCRequest): __slots__ = 'block' def __init__(self, controller: "DankMiddlewareController", params: Any, retry: bool = False) -> None: @@ -407,9 +425,9 @@ def should_retry(self, e: Exception) -> bool: elif any(err in f"{e}".lower() for err in constants.RETRY_ERRS): # TODO: use these exceptions to optimize for the user's node logger.debug('Dank too loud. Bisecting batch and retrying.') - elif isinstance(e, BadResponse) and ('invalid request' in f"{e}" or 'Parse error' in f"{e}" or 'invalid opcode: SHR' in f"{e}"): + elif isinstance(e, BadResponse) and (_needs_full_request_spec(e) or _is_call_revert(e)): pass - elif "error processing call Revert" not in f"{e}" and "429" not in f"{e}" and "resource not found" not in f"{e}": + elif "429" not in f"{e}": logger.warning(f"unexpected {e.__class__.__name__}: {e}") return len(self) > 1 @@ -794,10 +812,14 @@ def _log_exception(e: Exception) -> None: # NOTE: These errors are expected during normal use and are not indicative of any problem(s). No need to log them. # TODO: Better filter what we choose to log here dont_need_to_see_errs = constants.RETRY_ERRS + ['out of gas', 'non_empty_data', 'exceeding --rpc.returndata.limit', "'code': 429", 'payload too large'] - # We catch and correct these - dont_need_to_see_errs += ["invalid request"] - # We pass these down to the call they originated from - dont_need_to_see_errs += ["invalid ether transfer", "error processing call revert", "invalid opcode", "resource not found"] + + dont_need_to_see_errs += [ + # We catch and correct these + "invalid request", + # We pass these down to the call they originated from + *INDIVIDUAL_CALL_REVERT_STRINGS + ] + stre = str(e).lower() if any(err in stre for err in dont_need_to_see_errs): return