diff --git a/mango/client.py b/mango/client.py index 2443a9d..5a06b5b 100644 --- a/mango/client.py +++ b/mango/client.py @@ -63,6 +63,35 @@ class TooManyRequestsRateLimitException(RateLimitException): pass +# # πŸ₯­ BlockhashNotFoundException class +# +# A `BlockhashNotFoundException` exception allows trapping and handling exceptions when a blockhash is sent that +# the node doesn't understand. This can happen when the blockhash is too old (and the node no longer +# considers it 'recent') or when it's too new (and hasn't yet made it to the node that is responding). +# +class BlockhashNotFoundException(Exception): + def __init__(self, cluster_url: str, blockhash: typing.Optional[Blockhash] = None): + self.cluster_url: str = cluster_url + self.blockhash = blockhash + + def __str__(self) -> str: + return f"Β« π™±πš•πš˜πšŒπš”πš‘πšŠπšœπš‘π™½πš˜πšπ™΅πš˜πšžπš—πšπ™΄πš‘πšŒπšŽπš™πšπš’πš˜πš— [{self.blockhash}] on {self.cluster_url} Β»" + + +# # πŸ₯­ NodeIsBehindException class +# +# A `NodeIsBehindException` exception allows trapping and handling exceptions when a node is behind by too +# many slots. +# +class NodeIsBehindException(Exception): + def __init__(self, cluster_url: str, slots_behind: int): + self.cluster_url: str = cluster_url + self.slots_behind = slots_behind + + def __str__(self) -> str: + return f"Β« π™½πš˜πšπšŽπ™Έπšœπ™±πšŽπš‘πš’πš—πšπ™΄πš‘πšŒπšŽπš™πšπš’πš˜πš— [behind by {self.slots_behind}] on {self.cluster_url} Β»" + + # # πŸ₯­ TransactionException class # # A `TransactionException` exception that can provide additional error data, or at least better output @@ -307,6 +336,9 @@ class CompatibleClient(Client): ) self.logger.debug(f"Transaction ID response: {response}") return response + except BlockhashNotFoundException as blockhash_not_found_exception: + raise BlockhashNotFoundException(blockhash_not_found_exception.cluster_url, + transaction.recent_blockhash) from blockhash_not_found_exception except TransactionException as transaction_exception: raise TransactionException(transaction, transaction_exception.message, transaction_exception.code, transaction_exception.name, transaction_exception.rpc_method, @@ -344,9 +376,14 @@ class CompatibleClient(Client): error_message: str = response["error"]["message"] if "message" in response["error"] else "No message" exception_message: str = f"Transaction failed with: '{error_message}'" error_code: int = response["error"]["code"] if "code" in response["error"] else -1 + if error_code == -32005: + slots_behind: int = response["error"]["data"]["numSlotsBehind"] if "numSlotsBehind" in response["error"]["data"] else -1 + raise NodeIsBehindException(self.cluster_url, slots_behind) error_data: typing.Dict = response["error"]["data"] if "data" in response["error"] else {} error_accounts = error_data["accounts"] if "accounts" in error_data else "No accounts" error_err = error_data["err"] if "err" in error_data else "No error text returned" + if error_err == "BlockhashNotFound": + raise BlockhashNotFoundException(self.cluster_url) error_logs = error_data["logs"] if "logs" in error_data else "No logs" raise TransactionException(None, exception_message, error_code, self.name, method, data, response_text, error_accounts, error_err, error_logs)