bittensor-cli 8.2.0rc13__py3-none-any.whl → 8.2.0rc15__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -27,9 +27,10 @@ from bittensor_cli.src.bittensor.chain_data import (
27
27
  decode_hex_identity,
28
28
  DelegateInfoLite,
29
29
  DynamicInfo,
30
+ SubnetState,
30
31
  )
31
32
  from bittensor_cli.src import DelegatesDetails
32
- from bittensor_cli.src.bittensor.balances import Balance
33
+ from bittensor_cli.src.bittensor.balances import Balance, FixedPoint, fixed_to_float
33
34
  from bittensor_cli.src import Constants, defaults, TYPE_REGISTRY
34
35
  from bittensor_cli.src.bittensor.utils import (
35
36
  ss58_to_vec_u8,
@@ -227,7 +228,7 @@ class SubtensorInterface:
227
228
  else:
228
229
  return []
229
230
 
230
- async def get_stake_info_for_coldkey(
231
+ async def get_stake_for_coldkey(
231
232
  self,
232
233
  coldkey_ss58: str,
233
234
  block_hash: Optional[str] = None,
@@ -264,25 +265,61 @@ class SubtensorInterface:
264
265
  except ValueError:
265
266
  bytes_result = bytes.fromhex(hex_bytes_result)
266
267
 
267
- return StakeInfo.list_from_vec_u8(bytes_result)
268
+ stakes = StakeInfo.list_from_vec_u8(bytes_result)
269
+ return [stake for stake in stakes if stake.stake > 0]
268
270
 
269
271
  async def get_stake_for_coldkey_and_hotkey(
270
- self, hotkey_ss58: str, coldkey_ss58: str, block_hash: Optional[str]
272
+ self,
273
+ hotkey_ss58: str,
274
+ coldkey_ss58: str,
275
+ netuid: Optional[int] = None,
276
+ block_hash: Optional[str] = None,
271
277
  ) -> Balance:
272
278
  """
273
- Retrieves stake information associated with a specific coldkey and hotkey.
274
- :param hotkey_ss58: the hotkey SS58 address to query
275
- :param coldkey_ss58: the coldkey SS58 address to query
276
- :param block_hash: the hash of the blockchain block number for the query.
277
- :return: Stake Balance for the given coldkey and hotkey
279
+ Returns the stake under a coldkey - hotkey pairing.
280
+
281
+ Args:
282
+ hotkey_ss58 (str): The SS58 address of the hotkey.
283
+ coldkey_ss58 (str): The SS58 address of the coldkey.
284
+ netuid (Optional[int]): The subnet ID to filter by. If provided, only returns stake for this specific subnet.
285
+ block_hash (Optional[str]): The block hash at which to query the stake information.
286
+
287
+ Returns:
288
+ Balance: The stake under the coldkey - hotkey pairing.
278
289
  """
279
- _result = await self.substrate.query(
290
+ alpha_shares = await self.substrate.query(
280
291
  module="SubtensorModule",
281
- storage_function="Stake",
282
- params=[hotkey_ss58, coldkey_ss58],
292
+ storage_function="Alpha",
293
+ params=[hotkey_ss58, coldkey_ss58, netuid],
283
294
  block_hash=block_hash,
284
295
  )
285
- return Balance.from_rao(_result or 0)
296
+
297
+ hotkey_alpha = await self.substrate.query(
298
+ module="SubtensorModule",
299
+ storage_function="TotalHotkeyAlpha",
300
+ params=[hotkey_ss58, netuid],
301
+ block_hash=block_hash,
302
+ )
303
+
304
+ hotkey_shares = await self.substrate.query(
305
+ module="SubtensorModule",
306
+ storage_function="TotalHotkeyShares",
307
+ params=[hotkey_ss58, netuid],
308
+ block_hash=block_hash,
309
+ )
310
+
311
+ alpha_shares_as_float = fixed_to_float(alpha_shares or 0)
312
+ hotkey_shares_as_float = fixed_to_float(hotkey_shares or 0)
313
+
314
+ if hotkey_shares_as_float == 0:
315
+ return Balance.from_rao(0).set_unit(netuid=netuid)
316
+
317
+ stake = alpha_shares_as_float / hotkey_shares_as_float * (hotkey_alpha or 0)
318
+
319
+ return Balance.from_rao(int(stake)).set_unit(netuid=netuid)
320
+
321
+ # Alias
322
+ get_stake = get_stake_for_coldkey_and_hotkey
286
323
 
287
324
  async def query_runtime_api(
288
325
  self,
@@ -384,11 +421,11 @@ class SubtensorInterface:
384
421
 
385
422
  :return: {address: Balance objects}
386
423
  """
387
- sub_stakes = await self.get_stake_info_for_coldkeys(
424
+ sub_stakes = await self.get_stake_for_coldkeys(
388
425
  ss58_addresses, block_hash=block_hash
389
426
  )
390
427
  # Token pricing info
391
- dynamic_info = await self.get_all_subnet_dynamic_info()
428
+ dynamic_info = await self.all_subnets()
392
429
 
393
430
  results = {}
394
431
  for ss58, stake_info_list in sub_stakes.items():
@@ -552,6 +589,36 @@ class SubtensorInterface:
552
589
  )
553
590
  return result
554
591
 
592
+ async def get_subnet_state(
593
+ self, netuid: int, block_hash: Optional[str] = None
594
+ ) -> Optional["SubnetState"]:
595
+ """
596
+ Retrieves the state of a specific subnet within the Bittensor network.
597
+
598
+ Args:
599
+ netuid: The network UID of the subnet to query.
600
+ block_hash: The hash of the blockchain block number for the query.
601
+
602
+ Returns:
603
+ SubnetState object containing the subnet's state information, or None if the subnet doesn't exist.
604
+ """
605
+ hex_bytes_result = await self.query_runtime_api(
606
+ runtime_api="SubnetInfoRuntimeApi",
607
+ method="get_subnet_state",
608
+ params=[netuid],
609
+ block_hash=block_hash,
610
+ )
611
+
612
+ if hex_bytes_result is None:
613
+ return None
614
+
615
+ try:
616
+ bytes_result = bytes.fromhex(hex_bytes_result[2:])
617
+ except ValueError:
618
+ bytes_result = bytes.fromhex(hex_bytes_result)
619
+
620
+ return SubnetState.from_vec_u8(bytes_result)
621
+
555
622
  async def get_hyperparameter(
556
623
  self,
557
624
  param_name: str,
@@ -1256,27 +1323,6 @@ class SubtensorInterface:
1256
1323
 
1257
1324
  return DelegateInfoLite.list_from_vec_u8(result) # TODO this won't work yet
1258
1325
 
1259
- async def get_subnet_dynamic_info(
1260
- self, netuid: int, block_hash: Optional[str] = None
1261
- ) -> "DynamicInfo":
1262
- hex_bytes_result = await self.query_runtime_api(
1263
- runtime_api="SubnetInfoRuntimeApi",
1264
- method="get_dynamic_info",
1265
- params=[netuid],
1266
- block_hash=block_hash,
1267
- )
1268
-
1269
- if hex_bytes_result is None:
1270
- return None
1271
-
1272
- if hex_bytes_result.startswith("0x"):
1273
- bytes_result = bytes.fromhex(hex_bytes_result[2:])
1274
- else:
1275
- bytes_result = bytes.fromhex(hex_bytes_result)
1276
-
1277
- subnets = DynamicInfo.from_vec_u8(bytes_result)
1278
- return subnets
1279
-
1280
1326
  async def get_stake_for_coldkey_and_hotkey_on_netuid(
1281
1327
  self,
1282
1328
  hotkey_ss58: str,
@@ -1354,7 +1400,7 @@ class SubtensorInterface:
1354
1400
  results[hotkey_ss58][netuid] = value
1355
1401
  return results
1356
1402
 
1357
- async def get_stake_info_for_coldkeys(
1403
+ async def get_stake_for_coldkeys(
1358
1404
  self, coldkey_ss58_list: list[str], block_hash: Optional[str] = None
1359
1405
  ) -> Optional[dict[str, list[StakeInfo]]]:
1360
1406
  """
@@ -1392,7 +1438,9 @@ class SubtensorInterface:
1392
1438
 
1393
1439
  return StakeInfo.list_of_tuple_from_vec_u8(bytes_result) # type: ignore
1394
1440
 
1395
- async def get_all_subnet_dynamic_info(self, block_hash: Optional[str] = None) -> list["DynamicInfo"]:
1441
+ async def all_subnets(
1442
+ self, block_hash: Optional[str] = None
1443
+ ) -> list["DynamicInfo"]:
1396
1444
  query = await self.substrate.runtime_call(
1397
1445
  "SubnetInfoRuntimeApi",
1398
1446
  "get_all_dynamic_info",
@@ -1401,47 +1449,16 @@ class SubtensorInterface:
1401
1449
  subnets = DynamicInfo.list_from_vec_u8(bytes.fromhex(query.decode()[2:]))
1402
1450
  return subnets
1403
1451
 
1404
- async def get_global_weights(
1405
- self, netuids: list[int], block_hash: Optional[str] = None
1406
- ):
1407
- result = await self.substrate.query_multiple(
1408
- module="SubtensorModule",
1409
- storage_function="GlobalWeight",
1410
- params=[netuid for netuid in netuids],
1452
+ async def subnet(
1453
+ self, netuid: int, block_hash: Optional[str] = None
1454
+ ) -> "DynamicInfo":
1455
+ query = await self.substrate.runtime_call(
1456
+ "SubnetInfoRuntimeApi",
1457
+ "get_dynamic_info",
1458
+ params=[netuid],
1411
1459
  block_hash=block_hash,
1412
1460
  )
1413
- return {
1414
- netuid: u64_normalized_float(weight) for (netuid, weight) in result.items()
1415
- }
1416
-
1417
- async def get_subnet_tao(
1418
- self, netuid: Optional[int] = None, block_hash: Optional[str] = None
1419
- ) -> dict[int, Balance]:
1420
- """
1421
- Retrieves the total TAO for one or all subnets.
1422
-
1423
- Args:
1424
- netuid: Optional specific netuid to query. If None, returns data for all subnets.
1425
- block_hash: Optional block hash to query at.
1426
-
1427
- Returns:
1428
- Dictionary mapping netuid to its total TAO balance
1429
- """
1430
- if netuid is not None:
1431
- result = await self.substrate.query(
1432
- module="SubtensorModule",
1433
- storage_function="SubnetTAO",
1434
- params=[netuid],
1435
- block_hash=block_hash,
1436
- )
1437
- return {netuid: Balance.from_rao(result or 0)}
1438
- else:
1439
- results = await self.substrate.query_map(
1440
- module="SubtensorModule",
1441
- storage_function="SubnetTAO",
1442
- block_hash=block_hash,
1443
- )
1444
- return {netuid: Balance.from_rao(tao or 0) async for netuid, tao in results}
1461
+ return DynamicInfo.from_vec_u8(bytes.fromhex(query.decode()[2:]))
1445
1462
 
1446
1463
  async def get_owned_hotkeys(
1447
1464
  self,
@@ -2,6 +2,7 @@ import ast
2
2
  import math
3
3
  import os
4
4
  import sqlite3
5
+ import platform
5
6
  import webbrowser
6
7
  import sys
7
8
  from pathlib import Path
@@ -1202,17 +1203,36 @@ def is_valid_contact(contact: str) -> bool:
1202
1203
 
1203
1204
  def get_subnet_name(subnet_info) -> str:
1204
1205
  """Get the subnet name, prioritizing subnet_identity.subnet_name over subnet.subnet_name.
1205
-
1206
+
1206
1207
  Args:
1207
1208
  subnet: The subnet dynamic info
1208
-
1209
+
1209
1210
  Returns:
1210
1211
  str: The subnet name or empty string if no name is found
1211
1212
  """
1212
1213
  return (
1213
1214
  subnet_info.subnet_identity.subnet_name
1214
- if hasattr(subnet_info, 'subnet_identity')
1215
- and subnet_info.subnet_identity is not None
1215
+ if hasattr(subnet_info, "subnet_identity")
1216
+ and subnet_info.subnet_identity is not None
1216
1217
  and subnet_info.subnet_identity.subnet_name is not None
1217
1218
  else (subnet_info.subnet_name if subnet_info.subnet_name is not None else "")
1218
- )
1219
+ )
1220
+
1221
+
1222
+ def print_linux_dependency_message():
1223
+ """Prints the WebKit dependency message for Linux systems."""
1224
+ console.print("[red]This command requires WebKit dependencies on Linux.[/red]")
1225
+ console.print(
1226
+ "\nPlease install the required packages using one of the following commands based on your distribution:"
1227
+ )
1228
+ console.print("\nArch Linux / Manjaro:")
1229
+ console.print("[green]sudo pacman -S webkit2gtk[/green]")
1230
+ console.print("\nDebian / Ubuntu:")
1231
+ console.print("[green]sudo apt install libwebkit2gtk-4.0-dev[/green]")
1232
+ console.print("\nFedora / CentOS / AlmaLinux:")
1233
+ console.print("[green]sudo dnf install gtk3-devel webkit2gtk3-devel[/green]")
1234
+
1235
+
1236
+ def is_linux():
1237
+ """Returns True if the operating system is Linux."""
1238
+ return platform.system().lower() == "linux"