Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
25da3b2
improve workflow
May 13, 2025
a8ba38c
Merge pull request #2875 from opentensor/feat/roman/add-label-checker…
basfroman May 13, 2025
839e20b
add `is_subnet_active` in subtensors
May 13, 2025
3edd650
add `is_subnet_active` in SubtensorApi
May 13, 2025
8596c29
add `is_subnet_active` check to e2e tests
May 14, 2025
0b4ff5d
add unit test for `is_subnet_active`
May 14, 2025
6a9cf2e
Merge branch 'master' into feat/roman/add-is_subnet_active
basfroman May 14, 2025
52ca681
oops fix back
May 14, 2025
53a8642
Merge remote-tracking branch 'origin/feat/roman/add-is_subnet_active'…
May 14, 2025
59eb152
oops again
May 14, 2025
c2733c3
add if
May 14, 2025
c0167af
remove comment
May 14, 2025
ca79ebc
Merge pull request #2878 from opentensor/fix/roman/improve-mesure-wor…
basfroman May 14, 2025
176af07
Merge branch 'staging' into feat/roman/add-is_subnet_active
basfroman May 14, 2025
529d204
Merge pull request #2877 from opentensor/feat/roman/add-is_subnet_active
basfroman May 14, 2025
100e398
fix extrinsics
May 15, 2025
f6c175d
fix unittests
May 15, 2025
f39c77b
Merge pull request #2879 from opentensor/fix/roman/serve_axon
basfroman May 15, 2025
0cd1d27
update subtensors' init and docstrings
May 15, 2025
952f788
update SubtensorApi init and strings
May 15, 2025
d97b5b5
Update bittensor/core/subtensor.py
basfroman May 15, 2025
f65a706
Merge branch 'staging' into fix/roman/subtensor-api
basfroman May 15, 2025
5112425
Merge pull request #2880 from opentensor/fix/roman/subtensor-api
basfroman May 15, 2025
59d4a68
bumps version and changelog
ibraheem-abe May 15, 2025
3e33869
Merge pull request #2881 from opentensor/changelog/960
ibraheem-abe May 15, 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
6 changes: 3 additions & 3 deletions .github/workflows/monitor_requirements_size_master.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,16 @@ name: Monitor SDK Requirements Size

on:
pull_request:
types: [opened]
branches: [master]
types: [opened, labeled]
branches: [master, staging]

permissions:
pull-requests: write
contents: read

jobs:
measure-venv:
if: github.event_name == 'pull_request' && github.base_ref == 'master' || contains( github.event.pull_request.labels.*.name, 'show-venv-size')
runs-on: ubuntu-latest
strategy:
matrix:
Expand Down Expand Up @@ -54,7 +55,6 @@ jobs:
esac

comment-on-pr:
if: github.event_name == 'pull_request' && github.base_ref == 'master'
needs: measure-venv
runs-on: ubuntu-latest
steps:
Expand Down
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
# Changelog

## 9.5.0 /2025-05-15

* Add manual way to show the size of virtual environments in the PR by @basfroman in https://github.com/opentensor/bittensor/pull/2875
* Improve `Monitor SDK Requirements Size` workflow by @basfroman in https://github.com/opentensor/bittensor/pull/2878
* Add subtensor.is_subnet_active method by @basfroman in https://github.com/opentensor/bittensor/pull/2877
* Using `hotkey` instead of `coldkey` to sign extrinsic in `serve_axon` by @basfroman in https://github.com/opentensor/bittensor/pull/2879
* Rename argument `fallback_chains` to `fallback_endpoints` by @basfroman in https://github.com/opentensor/bittensor/pull/2880

**Full Changelog**: https://github.com/opentensor/bittensor/compare/v9.5.0...v9.6.0

## 9.5.0 /2025-05-12

## What's Changed
Expand Down
55 changes: 43 additions & 12 deletions bittensor/core/async_subtensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,19 +115,19 @@ def __init__(
network: Optional[str] = None,
config: Optional["Config"] = None,
log_verbose: bool = False,
fallback_chains: Optional[list[str]] = None,
fallback_endpoints: Optional[list[str]] = None,
retry_forever: bool = False,
_mock: bool = False,
):
"""
Initializes an instance of the AsyncSubtensor class.

Arguments:
network (str): The network name or type to connect to.
config (Optional[Config]): Configuration object for the AsyncSubtensor instance.
log_verbose (bool): Enables or disables verbose logging.
fallback_chains (list): List of fallback chains endpoints to use if no network is specified. Defaults to `None`.
retry_forever (bool): Whether to retry forever on connection errors. Defaults to `False`.
network: The network name or type to connect to.
config: Configuration object for the AsyncSubtensor instance.
log_verbose: Enables or disables verbose logging.
fallback_endpoints: List of fallback endpoints to use if default or provided network is not 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.

Raises:
Expand All @@ -148,7 +148,9 @@ def __init__(
f"chain_endpoint: [blue]{self.chain_endpoint}[/blue]..."
)
self.substrate = self._get_substrate(
fallback_chains=fallback_chains, retry_forever=retry_forever, _mock=_mock
fallback_endpoints=fallback_endpoints,
retry_forever=retry_forever,
_mock=_mock,
)
if self.log_verbose:
logging.info(
Expand Down Expand Up @@ -284,24 +286,24 @@ async def get_hyperparameter(

def _get_substrate(
self,
fallback_chains: Optional[list[str]] = None,
fallback_endpoints: Optional[list[str]] = None,
retry_forever: bool = False,
_mock: bool = False,
) -> Union[AsyncSubstrateInterface, RetryAsyncSubstrate]:
"""Creates the Substrate instance based on provided arguments.

Arguments:
fallback_chains (list): List of fallback chains endpoints to use if no network is specified. Defaults to `None`.
retry_forever (bool): Whether to retry forever on connection errors. Defaults to `False`.
fallback_endpoints: List of fallback endpoints to use if default or provided network is not 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.

Returns:
the instance of the SubstrateInterface or RetrySyncSubstrate class.
"""
if fallback_chains or retry_forever:
if fallback_endpoints or retry_forever:
return RetryAsyncSubstrate(
url=self.chain_endpoint,
fallback_chains=fallback_chains,
fallback_chains=fallback_endpoints,
ss58_format=SS58_FORMAT,
type_registry=TYPE_REGISTRY,
retry_forever=retry_forever,
Expand Down Expand Up @@ -2582,6 +2584,35 @@ async def is_hotkey_registered_on_subnet(
is not None
)

async def is_subnet_active(
self,
netuid: int,
block: Optional[int] = None,
block_hash: Optional[str] = None,
reuse_block: bool = False,
) -> bool:
"""Verify if subnet with provided netuid is active.

Args:
netuid (int): The unique identifier of the subnet.
block (Optional[int]): The blockchain block number for the query.
block_hash (Optional[str]): The blockchain block_hash representation of block id.
reuse_block (bool): Whether to reuse the last-used block hash.

Returns:
True if subnet is active, False otherwise.

This means whether the `start_call` was initiated or not.
"""
query = await self.query_subtensor(
name="FirstEmissionBlockNumber",
block=block,
block_hash=block_hash,
reuse_block=reuse_block,
params=[netuid],
)
return True if query and query.value > 0 else False

async def last_drand_round(self) -> Optional[int]:
"""
Retrieves the last drand round emitted in bittensor. This corresponds when committed weights will be revealed.
Expand Down
3 changes: 2 additions & 1 deletion bittensor/core/extrinsics/asyncex/serving.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ async def do_serve_axon(
wallet=wallet,
wait_for_inclusion=wait_for_inclusion,
wait_for_finalization=wait_for_finalization,
sign_with="hotkey",
period=period,
)
return success, message
Expand Down Expand Up @@ -140,7 +141,7 @@ async def serve_extrinsic(
f"Serving axon with: [blue]AxonInfo({wallet.hotkey.ss58_address}, {ip}:{port})[/blue] -> "
f"[green]{subtensor.network}:{netuid}[/green]"
)
success, message = do_serve_axon(
success, message = await do_serve_axon(
subtensor=subtensor,
wallet=wallet,
call_params=params,
Expand Down
1 change: 1 addition & 0 deletions bittensor/core/extrinsics/serving.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ def do_serve_axon(
wallet=wallet,
wait_for_inclusion=wait_for_inclusion,
wait_for_finalization=wait_for_finalization,
sign_with="hotkey",
period=period,
)
return success, message
Expand Down
45 changes: 33 additions & 12 deletions bittensor/core/subtensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,19 +117,19 @@ def __init__(
network: Optional[str] = None,
config: Optional["Config"] = None,
log_verbose: bool = False,
fallback_chains: Optional[list[str]] = None,
fallback_endpoints: Optional[list[str]] = None,
retry_forever: bool = False,
_mock: bool = False,
):
"""
Initializes an instance of the Subtensor class.

Arguments:
network (str): The network name or type to connect to.
config (Optional[Config]): Configuration object for the AsyncSubtensor instance.
log_verbose (bool): Enables or disables verbose logging.
fallback_chains (list): List of fallback chains endpoints to use if no network is specified. Defaults to `None`.
retry_forever (bool): Whether to retry forever on connection errors. Defaults to `False`.
network: The network name or type to connect to.
config: Configuration object for the AsyncSubtensor instance.
log_verbose: Enables or disables verbose logging.
fallback_endpoints: List of fallback endpoints to use if default or provided network is not 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.

Raises:
Expand All @@ -148,7 +148,9 @@ def __init__(
f"chain_endpoint: [blue]{self.chain_endpoint}[/blue]> ..."
)
self.substrate = self._get_substrate(
fallback_chains=fallback_chains, retry_forever=retry_forever, _mock=_mock
fallback_endpoints=fallback_endpoints,
retry_forever=retry_forever,
_mock=_mock,
)
if self.log_verbose:
logging.info(
Expand All @@ -167,28 +169,28 @@ def close(self):

def _get_substrate(
self,
fallback_chains: Optional[list[str]] = None,
fallback_endpoints: Optional[list[str]] = None,
retry_forever: bool = False,
_mock: bool = False,
) -> Union[SubstrateInterface, RetrySyncSubstrate]:
"""Creates the Substrate instance based on provided arguments.

Arguments:
fallback_chains (list): List of fallback chains endpoints to use if no network is specified. Defaults to `None`.
retry_forever (bool): Whether to retry forever on connection errors. Defaults to `False`.
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.

Returns:
the instance of the SubstrateInterface or RetrySyncSubstrate class.
"""
if fallback_chains or retry_forever:
if fallback_endpoints or retry_forever:
return RetrySyncSubstrate(
url=self.chain_endpoint,
ss58_format=SS58_FORMAT,
type_registry=TYPE_REGISTRY,
use_remote_preset=True,
chain_name="Bittensor",
fallback_chains=fallback_chains,
fallback_chains=fallback_endpoints,
retry_forever=retry_forever,
_mock=_mock,
)
Expand Down Expand Up @@ -2023,6 +2025,25 @@ def is_hotkey_registered_on_subnet(
is not None
)

def is_subnet_active(self, netuid: int, block: Optional[int] = None) -> bool:
"""Verify if subnet with provided netuid is active.

Args:
netuid (int): The unique identifier of the subnet.
block (Optional[int]): The blockchain block number for the query.

Returns:
True if subnet is active, False otherwise.

This means whether the `start_call` was initiated or not.
"""
query = self.query_subtensor(
name="FirstEmissionBlockNumber",
block=block,
params=[netuid],
)
return True if query and query.value > 0 else False

def last_drand_round(self) -> Optional[int]:
"""
Retrieves the last drand round emitted in bittensor. This corresponds when committed weights will be revealed.
Expand Down
23 changes: 14 additions & 9 deletions bittensor/core/subtensor_api/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@ class SubtensorApi:
network: The network to connect to. Defaults to `None` -> "finney".
config: Bittensor configuration object. Defaults to `None`.
legacy_methods: If `True`, all methods from the Subtensor class will be added to the root level of this class.
fallback_chains (list): List of fallback chains to use if no network is specified. Defaults to `None`.
retry_forever (bool): Whether to retry forever on connection errors. Defaults to `False`.
log_verbose (bool): Enables or disables verbose logging.
fallback_endpoints: List of fallback endpoints to use if default or provided network is not available. Defaults to `None`.
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.

Example:
Expand All @@ -54,10 +54,15 @@ class SubtensorApi:
subtensor = bt.SubtensorApi(legacy_methods=True)
print(subtensor.bonds(0))

# using `fallback_chains` or `retry_forever`
# using `fallback_endpoints` or `retry_forever`
import bittensor as bt


subtensor = bt.SubtensorApi(
network="finney",
fallback_endpoints=["wss://localhost:9945", "wss://some-other-endpoint:9945"],
retry_forever=True,
)
print(subtensor.block)
"""

def __init__(
Expand All @@ -66,13 +71,13 @@ def __init__(
config: Optional["Config"] = None,
async_subtensor: bool = False,
legacy_methods: bool = False,
fallback_chains: Optional[list[str]] = None,
fallback_endpoints: Optional[list[str]] = None,
retry_forever: bool = False,
log_verbose: bool = False,
mock: bool = False,
):
self.network = network
self._fallback_chains = fallback_chains
self._fallback_endpoints = fallback_endpoints
self._retry_forever = retry_forever
self._mock = mock
self.log_verbose = log_verbose
Expand Down Expand Up @@ -111,7 +116,7 @@ def _get_subtensor(self) -> Union["_Subtensor", "_AsyncSubtensor"]:
network=self.network,
config=self._config,
log_verbose=self.log_verbose,
fallback_chains=self._fallback_chains,
fallback_endpoints=self._fallback_endpoints,
retry_forever=self._retry_forever,
_mock=self._mock,
)
Expand All @@ -122,7 +127,7 @@ def _get_subtensor(self) -> Union["_Subtensor", "_AsyncSubtensor"]:
network=self.network,
config=self._config,
log_verbose=self.log_verbose,
fallback_chains=self._fallback_chains,
fallback_endpoints=self._fallback_endpoints,
retry_forever=self._retry_forever,
_mock=self._mock,
)
Expand Down
1 change: 1 addition & 0 deletions bittensor/core/subtensor_api/subnets.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ def __init__(self, subtensor: Union["_Subtensor", "_AsyncSubtensor"]):
self.get_uid_for_hotkey_on_subnet = subtensor.get_uid_for_hotkey_on_subnet
self.immunity_period = subtensor.immunity_period
self.is_hotkey_registered_on_subnet = subtensor.is_hotkey_registered_on_subnet
self.is_subnet_active = subtensor.is_subnet_active
self.max_weight_limit = subtensor.max_weight_limit
self.min_allowed_weights = subtensor.min_allowed_weights
self.recycle = subtensor.recycle
Expand Down
1 change: 1 addition & 0 deletions bittensor/core/subtensor_api/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ def add_legacy_methods(subtensor: "SubtensorApi"):
subtensor.is_hotkey_registered_on_subnet = (
subtensor._subtensor.is_hotkey_registered_on_subnet
)
subtensor.is_subnet_active = subtensor._subtensor.is_subnet_active
subtensor.last_drand_round = subtensor._subtensor.last_drand_round
subtensor.log_verbose = subtensor._subtensor.log_verbose
subtensor.max_weight_limit = subtensor._subtensor.max_weight_limit
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"

[project]
name = "bittensor"
version = "9.5.0"
version = "9.6.0"
description = "Bittensor"
readme = "README.md"
authors = [
Expand Down
12 changes: 11 additions & 1 deletion tests/e2e_tests/utils/e2e_test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ def validator(self, wallet, netuid):


def wait_to_start_call(
subtensor: "bittensor.Subtensor",
subtensor: "bittensor.SubtensorApi",
subnet_owner_wallet: "bittensor.Wallet",
netuid: int,
in_blocks: int = 10,
Expand All @@ -242,6 +242,11 @@ def wait_to_start_call(
f"Current block: [blue]{subtensor.block}[/blue]."
)

# make sure subnet isn't active
assert subtensor.subnets.is_subnet_active(netuid) is False, (
"Subnet is already active."
)

# make sure we passed start_call limit
subtensor.wait_for_block(subtensor.block + in_blocks + 1)
status, message = subtensor.start_call(
Expand All @@ -251,6 +256,11 @@ def wait_to_start_call(
wait_for_finalization=True,
)
assert status, message
# make sure subnet is active
assert subtensor.subnets.is_subnet_active(netuid), (
"Subnet did not activated after start call."
)

return True


Expand Down
Loading
Loading