Skip to content

Commit c8d3d59

Browse files
authored
Merge pull request #2894 from opentensor/feat/roman/add-get_subnet_info
Add `get_subnet_info`
2 parents fb51b48 + b0d159e commit c8d3d59

File tree

6 files changed

+172
-0
lines changed

6 files changed

+172
-0
lines changed

bittensor/core/async_subtensor.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1921,6 +1921,42 @@ async def get_stake_add_fee(
19211921
)
19221922
return Balance.from_rao(result)
19231923

1924+
async def get_subnet_info(
1925+
self,
1926+
netuid: int,
1927+
block: Optional[int] = None,
1928+
block_hash: Optional[str] = None,
1929+
reuse_block: bool = False,
1930+
) -> Optional["SubnetInfo"]:
1931+
"""
1932+
Retrieves detailed information about subnet within the Bittensor network.
1933+
This function provides comprehensive data on subnet, including its characteristics and operational parameters.
1934+
1935+
Arguments:
1936+
netuid: The unique identifier of the subnet.
1937+
block: The blockchain block number for the query.
1938+
block_hash (Optional[str]): The hash of the block to retrieve the stake from. Do not specify if using block
1939+
or reuse_block
1940+
reuse_block (bool): Whether to use the last-used block. Do not set if using block_hash or block.
1941+
1942+
Returns:
1943+
SubnetInfo: A SubnetInfo objects, each containing detailed information about a subnet.
1944+
1945+
Gaining insights into the subnet's details assists in understanding the network's composition, the roles of
1946+
different subnets, and their unique features.
1947+
"""
1948+
result = await self.query_runtime_api(
1949+
runtime_api="SubnetInfoRuntimeApi",
1950+
method="get_subnet_info_v2",
1951+
params=[netuid],
1952+
block=block,
1953+
block_hash=block_hash,
1954+
reuse_block=reuse_block,
1955+
)
1956+
if not result:
1957+
return None
1958+
return SubnetInfo.from_dict(result)
1959+
19241960
async def get_unstake_fee(
19251961
self,
19261962
amount: Balance,

bittensor/core/subtensor.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1507,6 +1507,33 @@ def get_stake_add_fee(
15071507
)
15081508
return Balance.from_rao(result)
15091509

1510+
def get_subnet_info(
1511+
self, netuid: int, block: Optional[int] = None
1512+
) -> Optional["SubnetInfo"]:
1513+
"""
1514+
Retrieves detailed information about subnet within the Bittensor network.
1515+
This function provides comprehensive data on subnet, including its characteristics and operational parameters.
1516+
1517+
Arguments:
1518+
netuid: The unique identifier of the subnet.
1519+
block: The blockchain block number for the query.
1520+
1521+
Returns:
1522+
SubnetInfo: A SubnetInfo objects, each containing detailed information about a subnet.
1523+
1524+
Gaining insights into the subnet's details assists in understanding the network's composition, the roles of
1525+
different subnets, and their unique features.
1526+
"""
1527+
result = self.query_runtime_api(
1528+
runtime_api="SubnetInfoRuntimeApi",
1529+
method="get_subnet_info_v2",
1530+
params=[netuid],
1531+
block=block,
1532+
)
1533+
if not result:
1534+
return None
1535+
return SubnetInfo.from_dict(result)
1536+
15101537
def get_unstake_fee(
15111538
self,
15121539
amount: Balance,

bittensor/core/subtensor_api/subnets.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ def __init__(self, subtensor: Union["_Subtensor", "_AsyncSubtensor"]):
2424
self.get_next_epoch_start_block = subtensor.get_next_epoch_start_block
2525
self.get_subnet_burn_cost = subtensor.get_subnet_burn_cost
2626
self.get_subnet_hyperparameters = subtensor.get_subnet_hyperparameters
27+
self.get_subnet_info = subtensor.get_subnet_info
2728
self.get_subnet_owner_hotkey = subtensor.get_subnet_owner_hotkey
2829
self.get_subnet_reveal_period_epochs = subtensor.get_subnet_reveal_period_epochs
2930
self.get_subnet_validator_permits = subtensor.get_subnet_validator_permits

bittensor/core/subtensor_api/utils.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ def add_legacy_methods(subtensor: "SubtensorApi"):
8484
subtensor.get_subnet_hyperparameters = (
8585
subtensor._subtensor.get_subnet_hyperparameters
8686
)
87+
subtensor.get_subnet_info = subtensor._subtensor.get_subnet_info
8788
subtensor.get_subnet_owner_hotkey = subtensor._subtensor.get_subnet_owner_hotkey
8889
subtensor.get_subnet_reveal_period_epochs = (
8990
subtensor._subtensor.get_subnet_reveal_period_epochs

tests/unit_tests/test_async_subtensor.py

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3314,3 +3314,59 @@ async def test_get_subnet_validator_permits_is_none(subtensor, mocker):
33143314
)
33153315

33163316
assert result is None
3317+
3318+
3319+
@pytest.mark.asyncio
3320+
async def test_get_subnet_info_success(mocker, subtensor):
3321+
"""Test get_subnet_info returns correct data when subnet information is found."""
3322+
# Prep
3323+
netuid = mocker.Mock()
3324+
block = mocker.Mock()
3325+
3326+
mocker.patch.object(subtensor, "query_runtime_api")
3327+
mocker.patch.object(
3328+
async_subtensor.SubnetInfo,
3329+
"from_dict",
3330+
)
3331+
3332+
# Call
3333+
result = await subtensor.get_subnet_info(netuid=netuid, block=block)
3334+
3335+
# Asserts
3336+
subtensor.query_runtime_api.assert_awaited_once_with(
3337+
runtime_api="SubnetInfoRuntimeApi",
3338+
method="get_subnet_info_v2",
3339+
params=[netuid],
3340+
block=block,
3341+
block_hash=None,
3342+
reuse_block=False,
3343+
)
3344+
async_subtensor.SubnetInfo.from_dict.assert_called_once_with(
3345+
subtensor.query_runtime_api.return_value,
3346+
)
3347+
assert result == async_subtensor.SubnetInfo.from_dict.return_value
3348+
3349+
3350+
@pytest.mark.asyncio
3351+
async def test_get_subnet_info_no_data(mocker, subtensor):
3352+
"""Test get_subnet_info returns None."""
3353+
# Prep
3354+
netuid = mocker.Mock()
3355+
block = mocker.Mock()
3356+
mocker.patch.object(async_subtensor.SubnetInfo, "from_dict")
3357+
mocker.patch.object(subtensor, "query_runtime_api", return_value=None)
3358+
3359+
# Call
3360+
result = await subtensor.get_subnet_info(netuid=netuid, block=block)
3361+
3362+
# Asserts
3363+
subtensor.query_runtime_api.assert_awaited_once_with(
3364+
runtime_api="SubnetInfoRuntimeApi",
3365+
method="get_subnet_info_v2",
3366+
params=[netuid],
3367+
block=block,
3368+
block_hash=None,
3369+
reuse_block=False,
3370+
)
3371+
async_subtensor.SubnetInfo.from_dict.assert_not_called()
3372+
assert result is None

tests/unit_tests/test_subtensor.py

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3668,3 +3668,54 @@ def test_is_subnet_active(subtensor, mocker, query_return, expected):
36683668
)
36693669

36703670
assert result == expected
3671+
3672+
3673+
# `geg_l_subnet_info` tests
3674+
def test_get_subnet_info_success(mocker, subtensor):
3675+
"""Test get_subnet_info returns correct data when subnet information is found."""
3676+
# Prep
3677+
netuid = mocker.Mock()
3678+
block = mocker.Mock()
3679+
3680+
mocker.patch.object(subtensor, "query_runtime_api")
3681+
mocker.patch.object(
3682+
subtensor_module.SubnetInfo,
3683+
"from_dict",
3684+
)
3685+
3686+
# Call
3687+
result = subtensor.get_subnet_info(netuid=netuid, block=block)
3688+
3689+
# Asserts
3690+
subtensor.query_runtime_api.assert_called_once_with(
3691+
runtime_api="SubnetInfoRuntimeApi",
3692+
method="get_subnet_info_v2",
3693+
params=[netuid],
3694+
block=block,
3695+
)
3696+
subtensor_module.SubnetInfo.from_dict.assert_called_once_with(
3697+
subtensor.query_runtime_api.return_value,
3698+
)
3699+
assert result == subtensor_module.SubnetInfo.from_dict.return_value
3700+
3701+
3702+
def test_get_subnet_info_no_data(mocker, subtensor):
3703+
"""Test get_subnet_info returns None."""
3704+
# Prep
3705+
netuid = mocker.Mock()
3706+
block = mocker.Mock()
3707+
mocker.patch.object(subtensor_module.SubnetInfo, "from_dict")
3708+
mocker.patch.object(subtensor, "query_runtime_api", return_value=None)
3709+
3710+
# Call
3711+
result = subtensor.get_subnet_info(netuid=netuid, block=block)
3712+
3713+
# Asserts
3714+
subtensor.query_runtime_api.assert_called_once_with(
3715+
runtime_api="SubnetInfoRuntimeApi",
3716+
method="get_subnet_info_v2",
3717+
params=[netuid],
3718+
block=block,
3719+
)
3720+
subtensor_module.SubnetInfo.from_dict.assert_not_called()
3721+
assert result is None

0 commit comments

Comments
 (0)