From 839e20be3f6681634aef2b9cea37c826b40f4b9f Mon Sep 17 00:00:00 2001 From: Roman Date: Tue, 13 May 2025 17:10:16 -0500 Subject: [PATCH 1/6] add `is_subnet_active` in subtensors --- bittensor/core/async_subtensor.py | 29 +++++++++++++++++++++++++++++ bittensor/core/subtensor.py | 19 +++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/bittensor/core/async_subtensor.py b/bittensor/core/async_subtensor.py index 1402e4c683..ea3b852b3d 100644 --- a/bittensor/core/async_subtensor.py +++ b/bittensor/core/async_subtensor.py @@ -2582,6 +2582,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. diff --git a/bittensor/core/subtensor.py b/bittensor/core/subtensor.py index 63634d9053..5c347774cf 100644 --- a/bittensor/core/subtensor.py +++ b/bittensor/core/subtensor.py @@ -2023,6 +2023,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. From 3edd650ebac06268a166c7cb0e2f8f4559efc708 Mon Sep 17 00:00:00 2001 From: Roman Date: Tue, 13 May 2025 17:11:13 -0500 Subject: [PATCH 2/6] add `is_subnet_active` in SubtensorApi --- bittensor/core/subtensor_api/subnets.py | 1 + bittensor/core/subtensor_api/utils.py | 1 + 2 files changed, 2 insertions(+) diff --git a/bittensor/core/subtensor_api/subnets.py b/bittensor/core/subtensor_api/subnets.py index c3333daf30..8b8c9121e7 100644 --- a/bittensor/core/subtensor_api/subnets.py +++ b/bittensor/core/subtensor_api/subnets.py @@ -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 diff --git a/bittensor/core/subtensor_api/utils.py b/bittensor/core/subtensor_api/utils.py index fdfde50697..3f8cc7d36d 100644 --- a/bittensor/core/subtensor_api/utils.py +++ b/bittensor/core/subtensor_api/utils.py @@ -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 From 8596c2952036b6c9996e03f47ef96ea113de3e4d Mon Sep 17 00:00:00 2001 From: Roman Date: Wed, 14 May 2025 10:36:12 -0500 Subject: [PATCH 3/6] add `is_subnet_active` check to e2e tests --- tests/e2e_tests/utils/e2e_test_utils.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/tests/e2e_tests/utils/e2e_test_utils.py b/tests/e2e_tests/utils/e2e_test_utils.py index 745c8977ab..8e5254535f 100644 --- a/tests/e2e_tests/utils/e2e_test_utils.py +++ b/tests/e2e_tests/utils/e2e_test_utils.py @@ -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, @@ -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( @@ -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 From 0b4ff5d41912a3255045d8a81d412deb80fe3b5a Mon Sep 17 00:00:00 2001 From: Roman Date: Wed, 14 May 2025 10:43:20 -0500 Subject: [PATCH 4/6] add unit test for `is_subnet_active` --- tests/unit_tests/test_subtensor.py | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/tests/unit_tests/test_subtensor.py b/tests/unit_tests/test_subtensor.py index 9085bf1122..0d902f0c73 100644 --- a/tests/unit_tests/test_subtensor.py +++ b/tests/unit_tests/test_subtensor.py @@ -3633,3 +3633,32 @@ def test_get_subnet_validator_permits_is_none(subtensor, mocker): ) assert result is None + + +@pytest.mark.parametrize( + "query_return, expected", + [ + [111, True], + [0, False], + ], +) +def test_is_subnet_active(subtensor, mocker, query_return, expected): + # preps + netuid = mocker.Mock() + block = mocker.Mock() + mocked_query_subtensor = mocker.MagicMock( + return_value=mocker.Mock(value=query_return) + ) + subtensor.query_subtensor = mocked_query_subtensor + + # call + result = subtensor.is_subnet_active(netuid=netuid, block=block) + + # Asserts + mocked_query_subtensor.assert_called_once_with( + name="FirstEmissionBlockNumber", + block=block, + params=[netuid], + ) + + assert result == expected From 52ca681bd73202a3bab582cbe0c68dd0eead6b52 Mon Sep 17 00:00:00 2001 From: Roman Date: Wed, 14 May 2025 10:46:46 -0500 Subject: [PATCH 5/6] oops fix back --- .github/workflows/monitor_requirements_size_master.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/monitor_requirements_size_master.yml b/.github/workflows/monitor_requirements_size_master.yml index 927dada0d8..301767ce7e 100644 --- a/.github/workflows/monitor_requirements_size_master.yml +++ b/.github/workflows/monitor_requirements_size_master.yml @@ -6,8 +6,8 @@ name: Monitor SDK Requirements Size on: pull_request: - types: [opened, labeled] - branches: [master, staging] + types: [opened] + branches: [master] permissions: pull-requests: write @@ -54,7 +54,7 @@ jobs: esac comment-on-pr: - if: github.event_name == 'pull_request' && github.base_ref == 'master' || contains( github.event.pull_request.labels.*.name, 'show-venv-size') + if: github.event_name == 'pull_request' && github.base_ref == 'master' needs: measure-venv runs-on: ubuntu-latest steps: From 59eb152d3a1d80cce1ea3a07ed98f8693fb0d144 Mon Sep 17 00:00:00 2001 From: Roman Date: Wed, 14 May 2025 10:48:15 -0500 Subject: [PATCH 6/6] oops again --- .github/workflows/monitor_requirements_size_master.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/monitor_requirements_size_master.yml b/.github/workflows/monitor_requirements_size_master.yml index 301767ce7e..927dada0d8 100644 --- a/.github/workflows/monitor_requirements_size_master.yml +++ b/.github/workflows/monitor_requirements_size_master.yml @@ -6,8 +6,8 @@ name: Monitor SDK Requirements Size on: pull_request: - types: [opened] - branches: [master] + types: [opened, labeled] + branches: [master, staging] permissions: pull-requests: write @@ -54,7 +54,7 @@ jobs: esac comment-on-pr: - if: github.event_name == 'pull_request' && github.base_ref == 'master' + if: github.event_name == 'pull_request' && github.base_ref == 'master' || contains( github.event.pull_request.labels.*.name, 'show-venv-size') needs: measure-venv runs-on: ubuntu-latest steps: