Skip to content

Commit ef47604

Browse files
Merge branch 'staging' into feat/abe/e2e-tests-1
2 parents 4d6ad65 + bcc7dc2 commit ef47604

File tree

4 files changed

+45
-56
lines changed

4 files changed

+45
-56
lines changed

bittensor/core/extrinsics/registration.py

+1-2
Original file line numberDiff line numberDiff line change
@@ -273,8 +273,7 @@ def _do_burned_register(
273273
"""
274274
Performs a burned register extrinsic call to the Subtensor chain.
275275
276-
This method sends a registration transaction to the Subtensor blockchain using the burned register mechanism. It
277-
retries the call up to three times with exponential backoff in case of failures.
276+
This method sends a registration transaction to the Subtensor blockchain using the burned register mechanism.
278277
279278
Args:
280279
self (bittensor.core.subtensor.Subtensor): Subtensor instance.

bittensor/core/subtensor.py

+1-22
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,3 @@
1-
# The MIT License (MIT)
2-
# Copyright © 2024 Opentensor Foundation
3-
#
4-
# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
5-
# documentation files (the “Software”), to deal in the Software without restriction, including without limitation
6-
# the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
7-
# and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
8-
#
9-
# The above copyright notice and this permission notice shall be included in all copies or substantial portions of
10-
# the Software.
11-
#
12-
# THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
13-
# THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
14-
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
15-
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
16-
# DEALINGS IN THE SOFTWARE.
17-
181
"""
192
The ``bittensor.core.subtensor.Subtensor`` module in Bittensor serves as a crucial interface for interacting with the
203
Bittensor blockchain, facilitating a range of operations essential for the decentralized machine learning network.
@@ -239,11 +222,7 @@ def _get_substrate(self):
239222

240223
except (ConnectionRefusedError, ssl.SSLError) as error:
241224
logging.error(
242-
f"Could not connect to {self.network} network with {self.chain_endpoint} chain endpoint.",
243-
)
244-
logging.info(
245-
"You can check if you have connectivity by running this command: nc -vz localhost "
246-
f"{self.chain_endpoint}"
225+
f"<red>Could not connect to</red> <blue>{self.network}</blue> <red>network with</red> <blue>{self.chain_endpoint}</blue> <red>chain endpoint.</red>",
247226
)
248227
raise ConnectionRefusedError(error.args)
249228

bittensor/utils/networking.py

+43-31
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,3 @@
1-
# The MIT License (MIT)
2-
# Copyright © 2024 Opentensor Foundation
3-
#
4-
# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
5-
# documentation files (the “Software”), to deal in the Software without restriction, including without limitation
6-
# the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
7-
# and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
8-
#
9-
# The above copyright notice and this permission notice shall be included in all copies or substantial portions of
10-
# the Software.
11-
#
12-
# THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
13-
# THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
14-
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
15-
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
16-
# DEALINGS IN THE SOFTWARE.
17-
181
"""Utils for handling local network with ip and ports."""
192

203
import json
@@ -26,6 +9,8 @@
269

2710
import netaddr
2811
import requests
12+
from retry import retry
13+
from websocket import WebSocketConnectionClosedException
2914

3015
from bittensor.utils.btlogging import logging
3116

@@ -178,22 +163,49 @@ def get_formatted_ws_endpoint_url(endpoint_url: Optional[str]) -> Optional[str]:
178163
def ensure_connected(func):
179164
"""Decorator ensuring the function executes with an active substrate connection."""
180165

166+
def is_connected(substrate) -> bool:
167+
"""Check if the substrate connection is active."""
168+
sock = substrate.websocket.sock
169+
return (
170+
sock is not None
171+
and sock.getsockopt(socket.SOL_SOCKET, socket.SO_ERROR) == 0
172+
)
173+
174+
@retry(
175+
exceptions=ConnectionRefusedError,
176+
tries=5,
177+
delay=5,
178+
backoff=1,
179+
logger=logging,
180+
)
181+
def reconnect_with_retries(self):
182+
"""Attempt to reconnect with retries using retry library."""
183+
logging.info("Attempting to reconnect to substrate...")
184+
self._get_substrate()
185+
186+
old_level = logging.get_level()
187+
logging.set_info()
188+
logging.success("Connection successfully restored!")
189+
logging.setLevel(old_level)
190+
181191
@wraps(func)
182192
def wrapper(self, *args, **kwargs):
183-
"""Wrapper function where `self` argument is Subtensor instance with the substrate connection."""
184-
# Check the socket state before method execution
185-
if (
186-
# connection was closed correctly
187-
self.substrate.websocket.sock is None
188-
# connection has a broken pipe
189-
or self.substrate.websocket.sock.getsockopt(
190-
socket.SOL_SOCKET, socket.SO_ERROR
191-
)
192-
!= 0
193-
):
194-
logging.debug("Reconnecting to substrate...")
193+
"""Wrapper function where `self` is expected to be a Subtensor instance."""
194+
if not is_connected(self.substrate):
195+
logging.debug("Substrate connection inactive. Attempting to reconnect...")
195196
self._get_substrate()
196-
# Execute the method if the connection is active or after reconnecting
197-
return func(self, *args, **kwargs)
197+
198+
try:
199+
return func(self, *args, **kwargs)
200+
except WebSocketConnectionClosedException:
201+
logging.warning(
202+
"WebSocket connection closed. Attempting to reconnect 5 times..."
203+
)
204+
try:
205+
reconnect_with_retries(self)
206+
return func(self, *args, **kwargs)
207+
except ConnectionRefusedError:
208+
logging.error("Unable to restore connection. Raising exception.")
209+
raise ConnectionRefusedError("Failed to reconnect to substrate.")
198210

199211
return wrapper

requirements/prod.txt

-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ wheel
22
setuptools~=70.0.0
33
aiohttp~=3.9
44
async-property==0.2.2
5-
backoff
65
bittensor-cli
76
bt-decode==0.2.0a0
87
colorama~=0.4.6

0 commit comments

Comments
 (0)