Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
1d5b075
Allow for use of the new archive backup endpoints specification.
thewhaleking Jun 6, 2025
c368f35
Ruff
thewhaleking Jun 6, 2025
fbacb1e
Merge remote-tracking branch 'origin/staging' into feat/thewhaleking/…
thewhaleking Jun 10, 2025
d9d57ea
Bump async-substrate-interface req
thewhaleking Jun 10, 2025
c8e13c6
Merge branch 'feat/thewhaleking/cleanup-websocket-integration-data' i…
thewhaleking Jun 10, 2025
4047dd9
Adds integration test for RetrySubtensor with Archive Node
thewhaleking Jun 10, 2025
af184ff
Merge branch 'staging' into feat/thewhaleking/retry-archive-node-support
thewhaleking Jun 10, 2025
a4410d4
Adds archive endpoints to SubtensorAPI
thewhaleking Jun 11, 2025
d5669e3
Merge branch 'staging' into feat/thewhaleking/retry-archive-node-support
thewhaleking Jun 11, 2025
5cfbb74
Adds ws_shutdown_timer arg to AsyncSubtensor and SubtensorAPI
thewhaleking Jun 11, 2025
e61c9af
Docstring.
thewhaleking Jun 11, 2025
e592660
Merge branch 'feat/thewhaleking/retry-archive-node-support' into feat…
thewhaleking Jun 11, 2025
952d956
Bumps async-substrate-interface requirement
thewhaleking Jun 13, 2025
1ebb466
Docstring update
thewhaleking Jun 13, 2025
bbaf299
Merge branch 'feat/thewhaleking/retry-archive-node-support' into feat…
thewhaleking Jun 13, 2025
12297af
Ruff
thewhaleking Jun 13, 2025
8fbf49b
Merge pull request #2917 from opentensor/feat/thewhaleking/new-websoc…
thewhaleking Jun 18, 2025
b6dfa80
Merge branch 'staging' into feat/thewhaleking/retry-archive-node-support
basfroman Jun 18, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 18 additions & 1 deletion bittensor/core/async_subtensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,8 @@ def __init__(
fallback_endpoints: Optional[list[str]] = None,
retry_forever: bool = False,
_mock: bool = False,
archive_endpoints: Optional[list[str]] = None,
websocket_shutdown_timer: float = 5.0,
):
"""
Initializes an instance of the AsyncSubtensor class.
Expand All @@ -132,6 +134,9 @@ def __init__(
Defaults to `None`.
retry_forever: Whether to retry forever on connection errors. Defaults to `False`.
_mock: Whether this is a mock instance. Mainly just for use in testing.
archive_endpoints: Similar to fallback_endpoints, but specifically only archive nodes. Will be used in cases
where you are requesting a block that is too old for your current (presumably lite) node. Defaults to
`None`

Raises:
Any exceptions raised during the setup, configuration, or connection process.
Expand All @@ -154,6 +159,8 @@ def __init__(
fallback_endpoints=fallback_endpoints,
retry_forever=retry_forever,
_mock=_mock,
archive_endpoints=archive_endpoints,
ws_shutdown_timer=websocket_shutdown_timer,
)
if self.log_verbose:
logging.info(
Expand Down Expand Up @@ -292,6 +299,8 @@ def _get_substrate(
fallback_endpoints: Optional[list[str]] = None,
retry_forever: bool = False,
_mock: bool = False,
archive_endpoints: Optional[list[str]] = None,
ws_shutdown_timer: float = 5.0,
) -> Union[AsyncSubstrateInterface, RetryAsyncSubstrate]:
"""Creates the Substrate instance based on provided arguments.

Expand All @@ -300,11 +309,16 @@ def _get_substrate(
Defaults to `None`.
retry_forever: Whether to retry forever on connection errors. Defaults to `False`.
_mock: Whether this is a mock instance. Mainly just for use in testing.
archive_endpoints: Similar to fallback_endpoints, but specifically only archive nodes. Will be used in cases
where you are requesting a block that is too old for your current (presumably lite) node. Defaults to
`None`
ws_shutdown_timer: Amount of time, in seconds, to wait after the last response from the chain to close the
connection.

Returns:
the instance of the SubstrateInterface or RetrySyncSubstrate class.
"""
if fallback_endpoints or retry_forever:
if fallback_endpoints or retry_forever or archive_endpoints:
return RetryAsyncSubstrate(
url=self.chain_endpoint,
fallback_chains=fallback_endpoints,
Expand All @@ -314,6 +328,8 @@ def _get_substrate(
use_remote_preset=True,
chain_name="Bittensor",
_mock=_mock,
archive_nodes=archive_endpoints,
ws_shutdown_timer=ws_shutdown_timer,
)
return AsyncSubstrateInterface(
url=self.chain_endpoint,
Expand All @@ -322,6 +338,7 @@ def _get_substrate(
use_remote_preset=True,
chain_name="Bittensor",
_mock=_mock,
ws_shutdown_timer=ws_shutdown_timer,
)

# Subtensor queries ===========================================================================================
Expand Down
18 changes: 14 additions & 4 deletions bittensor/core/subtensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,11 +117,12 @@ class Subtensor(SubtensorMixin):
def __init__(
self,
network: Optional[str] = None,
config: Optional["Config"] = None,
config: Optional[Config] = None,
log_verbose: bool = False,
fallback_endpoints: Optional[list[str]] = None,
retry_forever: bool = False,
_mock: bool = False,
archive_endpoints: Optional[list[str]] = None,
):
"""
Initializes an instance of the Subtensor class.
Expand All @@ -134,6 +135,9 @@ def __init__(
Defaults to `None`.
retry_forever: Whether to retry forever on connection errors. Defaults to `False`.
_mock: Whether this is a mock instance. Mainly just for use in testing.
archive_endpoints: Similar to fallback_endpoints, but specifically only archive nodes. Will be used in cases
where you are requesting a block that is too old for your current (presumably lite) node. Defaults to
`None`

Raises:
Any exceptions raised during the setup, configuration, or connection process.
Expand All @@ -154,6 +158,7 @@ def __init__(
fallback_endpoints=fallback_endpoints,
retry_forever=retry_forever,
_mock=_mock,
archive_endpoints=archive_endpoints,
)
if self.log_verbose:
logging.info(
Expand All @@ -175,19 +180,23 @@ def _get_substrate(
fallback_endpoints: Optional[list[str]] = None,
retry_forever: bool = False,
_mock: bool = False,
archive_endpoints: Optional[list[str]] = None,
) -> Union[SubstrateInterface, RetrySyncSubstrate]:
"""Creates the Substrate instance based on provided arguments.

Arguments:
fallback_endpoints: List of fallback chains endpoints to use if main network isn't available.
Defaults to `None`.
fallback_endpoints: List of fallback chains endpoints to use if main network isn't available. Defaults to
`None`.
retry_forever: Whether to retry forever on connection errors. Defaults to `False`.
_mock: Whether this is a mock instance. Mainly just for use in testing.
archive_endpoints: Similar to fallback_endpoints, but specifically only archive nodes. Will be used in cases
where you are requesting a block that is too old for your current (presumably lite) node. Defaults to
`None`

Returns:
the instance of the SubstrateInterface or RetrySyncSubstrate class.
"""
if fallback_endpoints or retry_forever:
if fallback_endpoints or retry_forever or archive_endpoints:
return RetrySyncSubstrate(
url=self.chain_endpoint,
ss58_format=SS58_FORMAT,
Expand All @@ -197,6 +206,7 @@ def _get_substrate(
fallback_chains=fallback_endpoints,
retry_forever=retry_forever,
_mock=_mock,
archive_nodes=archive_endpoints,
)
return SubstrateInterface(
url=self.chain_endpoint,
Expand Down
11 changes: 11 additions & 0 deletions bittensor/core/subtensor_api/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ class SubtensorApi:
retry_forever: Whether to retry forever on connection errors. Defaults to `False`.
log_verbose: Enables or disables verbose logging.
mock: Whether this is a mock instance. Mainly just for use in testing.
archive_endpoints: Similar to fallback_endpoints, but specifically only archive nodes. Will be used in cases
where you are requesting a block that is too old for your current (presumably lite) node. Defaults to `None`
websocket_shutdown_timer: Amount of time, in seconds, to wait after the last response from the chain to close
the connection. Only applicable to AsyncSubtensor.

Example:
# sync version
Expand Down Expand Up @@ -75,10 +79,14 @@ def __init__(
retry_forever: bool = False,
log_verbose: bool = False,
mock: bool = False,
archive_endpoints: Optional[list[str]] = None,
websocket_shutdown_timer: float = 5.0,
):
self.network = network
self._fallback_endpoints = fallback_endpoints
self._archive_endpoints = archive_endpoints
self._retry_forever = retry_forever
self._ws_shutdown_timer = websocket_shutdown_timer
self._mock = mock
self.log_verbose = log_verbose
self.is_async = async_subtensor
Expand Down Expand Up @@ -119,6 +127,8 @@ def _get_subtensor(self) -> Union["_Subtensor", "_AsyncSubtensor"]:
fallback_endpoints=self._fallback_endpoints,
retry_forever=self._retry_forever,
_mock=self._mock,
archive_endpoints=self._archive_endpoints,
websocket_shutdown_timer=self._ws_shutdown_timer,
)
self.initialize = _subtensor.initialize
return _subtensor
Expand All @@ -130,6 +140,7 @@ def _get_subtensor(self) -> Union["_Subtensor", "_AsyncSubtensor"]:
fallback_endpoints=self._fallback_endpoints,
retry_forever=self._retry_forever,
_mock=self._mock,
archive_endpoints=self._archive_endpoints,
)

def _determine_chain_endpoint(self) -> str:
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ dependencies = [
"uvicorn",
"bittensor-drand>=0.5.0",
"bittensor-wallet>=3.0.8",
"async-substrate-interface>=1.2.0"
"async-substrate-interface>=1.3.1"
]

[project.optional-dependencies]
Expand Down
4 changes: 4 additions & 0 deletions tests/helpers/helpers.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import asyncio
import itertools
import json
import time
from collections import deque
Expand Down Expand Up @@ -204,6 +205,9 @@ def recv(self, *args, **kwargs):
response = WEBSOCKET_RESPONSES[self.seed][item["method"]][
json.dumps(item["params"])
]
if isinstance(response, itertools.cycle):
# Allows us to cycle through different responses for the same method/params combo
response = next(response)
response["id"] = _id
return json.dumps(response)
except (KeyError, TypeError):
Expand Down
Loading