henrytirla / Decentralized-Exchange-Trading-Scripts

Useful scripts to automate trading on different DEX
https://t.me/dexpnl_bot
MIT License
366 stars 154 forks source link

Workaround for connection errors #5

Closed Artemyin closed 8 months ago

Artemyin commented 8 months ago

Hi, check some updates.

HTTPStatusError Make a workaround for the RPC API client. Catch SolandaRPCexception for any case errors, wait some time, and try again

def main():
...
try:
    get_tokens(signature, RaydiumLPV4)
except SolanaRpcException as err:
    # Omitting httpx.HTTPStatusError: Client error '429 Too Many Requests'
    # Sleep 5 sec, and try connect again
    sleep(5)
    continue
...

ProtocolError and ConnectionClosedError Also, I caught some spontaneous errors with WebSockets, you could check Traceback. Unfortunately, my knowledge isn't enough to find the root cause of these errors. I changed context manager to for loop, so I use websocket_api.connect as an infinite asynchronous iterator to reconnect automatically on errors

def main():
...
try:
    ...
    async for i, signature in enumerate(process_messages(websocket, log_instruction)):
        try:
            get_tokens(signature, RaydiumLPV4)
        except SolanaRpcException as err:
            sleep(5)
            continue
except (ProtocolError, ConnectionClosedError) as err:
    # Restart socket connection if error happend
    continue
...
Traceback

``` Traceback (most recent call last): File "/home/artemii/code/solana/env/lib/python3.11/site-packages/websockets/legacy/protocol.py", line 959, in transfer_data message = await self.read_message() ^^^^^^^^^^^^^^^^^^^^^^^^^ File "/home/artemii/code/solana/env/lib/python3.11/site-packages/websockets/legacy/protocol.py", line 1029, in read_message frame = await self.read_data_frame(max_size=self.max_size) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/home/artemii/code/solana/env/lib/python3.11/site-packages/websockets/legacy/protocol.py", line 1110, in read_data_frame self.close_rcvd = Close.parse(frame.data) ^^^^^^^^^^^^^^^^^^^^^^^ File "/home/artemii/code/solana/env/lib/python3.11/site-packages/websockets/frames.py", line 425, in parse close.check() File "/home/artemii/code/solana/env/lib/python3.11/site-packages/websockets/frames.py", line 449, in check raise exceptions.ProtocolError("invalid status code") websockets.exceptions.ProtocolError: invalid status code The above exception was the direct cause of the following exception: Traceback (most recent call last): File "/home/artemii/code/solana/newlpcreated.py", line 193, in asyncio.run(main()) File "/usr/local/lib/python3.11/asyncio/runners.py", line 190, in run return runner.run(main) ^^^^^^^^^^^^^^^^ File "/usr/local/lib/python3.11/asyncio/runners.py", line 118, in run return self._loop.run_until_complete(task) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/local/lib/python3.11/asyncio/base_events.py", line 653, in run_until_complete return future.result() ^^^^^^^^^^^^^^^ File "/home/artemii/code/solana/newlpcreated.py", line 70, in main await websocket.logs_unsubscribe(subscription_id) File "/home/artemii/code/solana/env/lib/python3.11/site-packages/solana/rpc/websocket_api.py", line 176, in logs_unsubscribe await self.send_data(req) File "/home/artemii/code/solana/env/lib/python3.11/site-packages/solana/rpc/websocket_api.py", line 98, in send_data await super().send(to_send) # type: ignore ^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/home/artemii/code/solana/env/lib/python3.11/site-packages/websockets/legacy/protocol.py", line 635, in send await self.ensure_open() File "/home/artemii/code/solana/env/lib/python3.11/site-packages/websockets/legacy/protocol.py", line 935, in ensure_open raise self.connection_closed_exc() websockets.exceptions.ConnectionClosedError: sent 1002 (protocol error); no close frame received ```

Logging Add logging. It the first time I have used it, thus it look creepy. Initialize it with logging level DEBUG, but after calling await subscribe_to_logs() i switch level to INFO, intend is my desire to check parameters of connections.

...
logging.basicConfig(filename='app.log', filemode='a', level=logging.DEBUG)
....
logging.getLogger().setLevel(logging.INFO)  # Logging
...

then i logging some truncated information

...
logging.info(value.signature)
logging.info(log)
...
logging.info(filtred_instuctions)
...
logging.info(f"\n Token0: {Token0}, \n Token1: {Token1}, \n Pair: {Pair}")
...

Also I start write complete responses in json into files.

...
async def process_messages():
...
with open("messages.json", 'a', encoding='utf-8') as raw_messages:  
    raw_messages.write(f"signature: {value.signature} \n")
    raw_messages.write(msg[0].to_json())
    raw_messages.write("\n ########## \n")
...
...
def get_tokens():
...
with open("transactions.json", 'a', encoding='utf-8') as raw_transactions:
    raw_transactions.write(f"signature: {signature}\n")
    raw_transactions.write(transaction.to_json())        
    raw_transactions.write("\n ########## \n")
...
Artemyin commented 8 months ago

I catch another very rare error. Sometimes, transactions in def get_tokens() returns null value in result.value that cause an error inside get_instructions() function. guess that adding simple check before calling get_instructions() can help omit this problem

def get_tokens():
...
transaction = solana_client.get_transaction(...)
...
#  check for empty result or None value in transaction.value
if not transaction.value:
    print("No data, empty result")
    logging.error("empty result %s", transaction)
    return None
instructions = get_instructions(transaction)
...
henrytirla commented 8 months ago

You have done a great job. Thank you for your contribution