bittensor-cli 8.4.3__py3-none-any.whl → 9.0.0__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.
Files changed (33) hide show
  1. bittensor_cli/__init__.py +1 -1
  2. bittensor_cli/cli.py +1827 -1392
  3. bittensor_cli/src/__init__.py +623 -168
  4. bittensor_cli/src/bittensor/balances.py +41 -8
  5. bittensor_cli/src/bittensor/chain_data.py +557 -428
  6. bittensor_cli/src/bittensor/extrinsics/registration.py +129 -23
  7. bittensor_cli/src/bittensor/extrinsics/root.py +3 -3
  8. bittensor_cli/src/bittensor/extrinsics/transfer.py +6 -11
  9. bittensor_cli/src/bittensor/minigraph.py +46 -8
  10. bittensor_cli/src/bittensor/subtensor_interface.py +567 -250
  11. bittensor_cli/src/bittensor/utils.py +399 -25
  12. bittensor_cli/src/commands/stake/__init__.py +154 -0
  13. bittensor_cli/src/commands/stake/add.py +625 -0
  14. bittensor_cli/src/commands/stake/children_hotkeys.py +103 -75
  15. bittensor_cli/src/commands/stake/list.py +687 -0
  16. bittensor_cli/src/commands/stake/move.py +1000 -0
  17. bittensor_cli/src/commands/stake/remove.py +1146 -0
  18. bittensor_cli/src/commands/subnets/__init__.py +0 -0
  19. bittensor_cli/src/commands/subnets/price.py +867 -0
  20. bittensor_cli/src/commands/subnets/subnets.py +2028 -0
  21. bittensor_cli/src/commands/sudo.py +554 -12
  22. bittensor_cli/src/commands/wallets.py +225 -531
  23. bittensor_cli/src/commands/weights.py +2 -2
  24. {bittensor_cli-8.4.3.dist-info → bittensor_cli-9.0.0.dist-info}/METADATA +7 -4
  25. bittensor_cli-9.0.0.dist-info/RECORD +34 -0
  26. bittensor_cli/src/bittensor/async_substrate_interface.py +0 -2748
  27. bittensor_cli/src/commands/root.py +0 -1752
  28. bittensor_cli/src/commands/stake/stake.py +0 -1448
  29. bittensor_cli/src/commands/subnets.py +0 -897
  30. bittensor_cli-8.4.3.dist-info/RECORD +0 -31
  31. {bittensor_cli-8.4.3.dist-info → bittensor_cli-9.0.0.dist-info}/WHEEL +0 -0
  32. {bittensor_cli-8.4.3.dist-info → bittensor_cli-9.0.0.dist-info}/entry_points.txt +0 -0
  33. {bittensor_cli-8.4.3.dist-info → bittensor_cli-9.0.0.dist-info}/top_level.txt +0 -0
@@ -24,9 +24,11 @@ import numpy as np
24
24
  from rich.prompt import Confirm
25
25
  from rich.console import Console
26
26
  from rich.status import Status
27
- from substrateinterface.exceptions import SubstrateRequestException
27
+ from async_substrate_interface.errors import SubstrateRequestException
28
28
 
29
+ from bittensor_cli.src import COLOR_PALETTE
29
30
  from bittensor_cli.src.bittensor.chain_data import NeuronInfo
31
+ from bittensor_cli.src.bittensor.balances import Balance
30
32
  from bittensor_cli.src.bittensor.utils import (
31
33
  console,
32
34
  err_console,
@@ -436,7 +438,7 @@ async def is_hotkey_registered(
436
438
  subtensor: "SubtensorInterface", netuid: int, hotkey_ss58: str
437
439
  ) -> bool:
438
440
  """Checks to see if the hotkey is registered on a given netuid"""
439
- _result = await subtensor.substrate.query(
441
+ _result = await subtensor.query(
440
442
  module="SubtensorModule",
441
443
  storage_function="Uids",
442
444
  params=[netuid, hotkey_ss58],
@@ -487,22 +489,18 @@ async def register_extrinsic(
487
489
  """
488
490
 
489
491
  async def get_neuron_for_pubkey_and_subnet():
490
- uid = await subtensor.substrate.query(
492
+ uid = await subtensor.query(
491
493
  "SubtensorModule", "Uids", [netuid, wallet.hotkey.ss58_address]
492
494
  )
493
495
  if uid is None:
494
496
  return NeuronInfo.get_null_neuron()
495
497
 
496
- params = [netuid, uid]
497
- json_body = await subtensor.substrate.rpc_request(
498
- method="neuronInfo_getNeuron",
499
- params=params,
498
+ result = await subtensor.neuron_for_uid(
499
+ uid=uid,
500
+ netuid=netuid,
501
+ block_hash=subtensor.substrate.last_block_hash,
500
502
  )
501
-
502
- if not (result := json_body.get("result", None)):
503
- return NeuronInfo.get_null_neuron()
504
-
505
- return NeuronInfo.from_vec_u8(bytes(result))
503
+ return result
506
504
 
507
505
  print_verbose("Checking subnet status")
508
506
  if not await subtensor.subnet_exists(netuid):
@@ -526,9 +524,9 @@ async def register_extrinsic(
526
524
  if prompt:
527
525
  if not Confirm.ask(
528
526
  f"Continue Registration?\n"
529
- f" hotkey ({wallet.hotkey_str}):\t[bold white]{wallet.hotkey.ss58_address}[/bold white]\n"
530
- f" coldkey ({wallet.name}):\t[bold white]{wallet.coldkeypub.ss58_address}[/bold white]\n"
531
- f" network:\t\t[bold white]{subtensor.network}[/bold white]"
527
+ f" hotkey [{COLOR_PALETTE['GENERAL']['HOTKEY']}]({wallet.hotkey_str})[/{COLOR_PALETTE['GENERAL']['HOTKEY']}]:\t[{COLOR_PALETTE['GENERAL']['HOTKEY']}]{wallet.hotkey.ss58_address}[/{COLOR_PALETTE['GENERAL']['HOTKEY']}]\n"
528
+ f" coldkey [{COLOR_PALETTE['GENERAL']['COLDKEY']}]({wallet.name})[/{COLOR_PALETTE['GENERAL']['COLDKEY']}]:\t[{COLOR_PALETTE['GENERAL']['COLDKEY']}]{wallet.coldkeypub.ss58_address}[/{COLOR_PALETTE['GENERAL']['COLDKEY']}]\n"
529
+ f" network:\t\t[{COLOR_PALETTE['GENERAL']['LINKS']}]{subtensor.network}[/{COLOR_PALETTE['GENERAL']['LINKS']}]\n"
532
530
  ):
533
531
  return False
534
532
 
@@ -581,7 +579,7 @@ async def register_extrinsic(
581
579
  )
582
580
  if is_registered:
583
581
  err_console.print(
584
- f":white_heavy_check_mark: [green]Already registered on netuid:{netuid}[/green]"
582
+ f":white_heavy_check_mark: [dark_sea_green3]Already registered on netuid:{netuid}[/dark_sea_green3]"
585
583
  )
586
584
  return True
587
585
 
@@ -625,8 +623,8 @@ async def register_extrinsic(
625
623
 
626
624
  if "HotKeyAlreadyRegisteredInSubNet" in err_msg:
627
625
  console.print(
628
- f":white_heavy_check_mark: [green]Already Registered on "
629
- f"[bold]subnet:{netuid}[/bold][/green]"
626
+ f":white_heavy_check_mark: [dark_sea_green3]Already Registered on "
627
+ f"[bold]subnet:{netuid}[/bold][/dark_sea_green3]"
630
628
  )
631
629
  return True
632
630
  err_console.print(
@@ -644,7 +642,7 @@ async def register_extrinsic(
644
642
  )
645
643
  if is_registered:
646
644
  console.print(
647
- ":white_heavy_check_mark: [green]Registered[/green]"
645
+ ":white_heavy_check_mark: [dark_sea_green3]Registered[/dark_sea_green3]"
648
646
  )
649
647
  return True
650
648
  else:
@@ -671,6 +669,114 @@ async def register_extrinsic(
671
669
  return False
672
670
 
673
671
 
672
+ async def burned_register_extrinsic(
673
+ subtensor: "SubtensorInterface",
674
+ wallet: Wallet,
675
+ netuid: int,
676
+ old_balance: Balance,
677
+ wait_for_inclusion: bool = True,
678
+ wait_for_finalization: bool = True,
679
+ prompt: bool = False,
680
+ ) -> bool:
681
+ """Registers the wallet to chain by recycling TAO.
682
+
683
+ :param subtensor: The SubtensorInterface object to use for the call, initialized
684
+ :param wallet: Bittensor wallet object.
685
+ :param netuid: The `netuid` of the subnet to register on.
686
+ :param old_balance: The wallet balance prior to the registration burn.
687
+ :param wait_for_inclusion: If set, waits for the extrinsic to enter a block before returning `True`, or returns
688
+ `False` if the extrinsic fails to enter the block within the timeout.
689
+ :param wait_for_finalization: If set, waits for the extrinsic to be finalized on the chain before returning `True`,
690
+ or returns `False` if the extrinsic fails to be finalized within the timeout.
691
+ :param prompt: If `True`, the call waits for confirmation from the user before proceeding.
692
+
693
+ :return: Flag is `True` if extrinsic was finalized or included in the block. If we did not wait for
694
+ finalization/inclusion, the response is `True`.
695
+ """
696
+
697
+ if not (unlock_status := unlock_key(wallet, print_out=False)).success:
698
+ return False, unlock_status.message
699
+
700
+ with console.status(
701
+ f":satellite: Checking Account on [bold]subnet:{netuid}[/bold]...",
702
+ spinner="aesthetic",
703
+ ) as status:
704
+ my_uid = await subtensor.query(
705
+ "SubtensorModule", "Uids", [netuid, wallet.hotkey.ss58_address]
706
+ )
707
+
708
+ print_verbose("Checking if already registered", status)
709
+ neuron = await subtensor.neuron_for_uid(
710
+ uid=my_uid,
711
+ netuid=netuid,
712
+ block_hash=subtensor.substrate.last_block_hash,
713
+ )
714
+
715
+ if not neuron.is_null:
716
+ console.print(
717
+ ":white_heavy_check_mark: [dark_sea_green3]Already Registered[/dark_sea_green3]:\n"
718
+ f"uid: [{COLOR_PALETTE['GENERAL']['NETUID_EXTRA']}]{neuron.uid}[/{COLOR_PALETTE['GENERAL']['NETUID_EXTRA']}]\n"
719
+ f"netuid: [{COLOR_PALETTE['GENERAL']['NETUID']}]{neuron.netuid}[/{COLOR_PALETTE['GENERAL']['NETUID']}]\n"
720
+ f"hotkey: [{COLOR_PALETTE['GENERAL']['HOTKEY']}]{neuron.hotkey}[/{COLOR_PALETTE['GENERAL']['HOTKEY']}]\n"
721
+ f"coldkey: [{COLOR_PALETTE['GENERAL']['COLDKEY']}]{neuron.coldkey}[/{COLOR_PALETTE['GENERAL']['COLDKEY']}]"
722
+ )
723
+ return True
724
+
725
+ with console.status(
726
+ ":satellite: Recycling TAO for Registration...", spinner="aesthetic"
727
+ ):
728
+ call = await subtensor.substrate.compose_call(
729
+ call_module="SubtensorModule",
730
+ call_function="burned_register",
731
+ call_params={
732
+ "netuid": netuid,
733
+ "hotkey": wallet.hotkey.ss58_address,
734
+ },
735
+ )
736
+ success, err_msg = await subtensor.sign_and_send_extrinsic(
737
+ call, wallet, wait_for_inclusion, wait_for_finalization
738
+ )
739
+
740
+ if not success:
741
+ err_console.print(f":cross_mark: [red]Failed[/red]: {err_msg}")
742
+ await asyncio.sleep(0.5)
743
+ return False
744
+ # Successful registration, final check for neuron and pubkey
745
+ else:
746
+ with console.status(":satellite: Checking Balance...", spinner="aesthetic"):
747
+ block_hash = await subtensor.substrate.get_chain_head()
748
+ new_balance, netuids_for_hotkey, my_uid = await asyncio.gather(
749
+ subtensor.get_balance(
750
+ wallet.coldkeypub.ss58_address,
751
+ block_hash=block_hash,
752
+ reuse_block=False,
753
+ ),
754
+ subtensor.get_netuids_for_hotkey(
755
+ wallet.hotkey.ss58_address, block_hash=block_hash
756
+ ),
757
+ subtensor.query(
758
+ "SubtensorModule", "Uids", [netuid, wallet.hotkey.ss58_address]
759
+ ),
760
+ )
761
+
762
+ console.print(
763
+ "Balance:\n"
764
+ f" [blue]{old_balance}[/blue] :arrow_right: [{COLOR_PALETTE['STAKE']['STAKE_AMOUNT']}]{new_balance}[/{COLOR_PALETTE['STAKE']['STAKE_AMOUNT']}]"
765
+ )
766
+
767
+ if len(netuids_for_hotkey) > 0:
768
+ console.print(
769
+ f":white_heavy_check_mark: [green]Registered on netuid {netuid} with UID {my_uid}[/green]"
770
+ )
771
+ return True
772
+ else:
773
+ # neuron not found, try again
774
+ err_console.print(
775
+ ":cross_mark: [red]Unknown error. Neuron not found.[/red]"
776
+ )
777
+ return False
778
+
779
+
674
780
  async def run_faucet_extrinsic(
675
781
  subtensor: "SubtensorInterface",
676
782
  wallet: Wallet,
@@ -806,8 +912,8 @@ async def run_faucet_extrinsic(
806
912
  wallet.coldkeypub.ss58_address
807
913
  )
808
914
  console.print(
809
- f"Balance: [blue]{old_balance[wallet.coldkeypub.ss58_address]}[/blue] :arrow_right:"
810
- f" [green]{new_balance[wallet.coldkeypub.ss58_address]}[/green]"
915
+ f"Balance: [blue]{old_balance}[/blue] :arrow_right:"
916
+ f" [green]{new_balance}[/green]"
811
917
  )
812
918
  old_balance = new_balance
813
919
 
@@ -912,7 +1018,7 @@ async def _block_solver(
912
1018
  limit = int(math.pow(2, 256)) - 1
913
1019
 
914
1020
  # Establish communication queues
915
- ## See the _Solver class for more information on the queues.
1021
+ # See the _Solver class for more information on the queues.
916
1022
  stop_event = Event()
917
1023
  stop_event.clear()
918
1024
 
@@ -928,7 +1034,7 @@ async def _block_solver(
928
1034
  )
929
1035
 
930
1036
  if cuda:
931
- ## Create a worker per CUDA device
1037
+ # Create a worker per CUDA device
932
1038
  solvers = [
933
1039
  _CUDASolver(
934
1040
  i,
@@ -26,7 +26,7 @@ from numpy.typing import NDArray
26
26
  from rich.prompt import Confirm
27
27
  from rich.table import Table, Column
28
28
  from scalecodec import ScaleBytes, U16, Vec
29
- from substrateinterface.exceptions import SubstrateRequestException
29
+ from async_substrate_interface.errors import SubstrateRequestException
30
30
 
31
31
  from bittensor_cli.src.bittensor.subtensor_interface import SubtensorInterface
32
32
  from bittensor_cli.src.bittensor.extrinsics.registration import is_hotkey_registered
@@ -339,7 +339,7 @@ async def root_register_extrinsic(
339
339
 
340
340
  # Successful registration, final check for neuron and pubkey
341
341
  else:
342
- uid = await subtensor.substrate.query(
342
+ uid = await subtensor.query(
343
343
  module="SubtensorModule",
344
344
  storage_function="Uids",
345
345
  params=[0, wallet.hotkey.ss58_address],
@@ -416,7 +416,7 @@ async def set_root_weights_extrinsic(
416
416
  else:
417
417
  return False, await response.error_message
418
418
 
419
- my_uid = await subtensor.substrate.query(
419
+ my_uid = await subtensor.query(
420
420
  "SubtensorModule", "Uids", [0, wallet.hotkey.ss58_address]
421
421
  )
422
422
 
@@ -2,7 +2,7 @@ import asyncio
2
2
 
3
3
  from bittensor_wallet import Wallet
4
4
  from rich.prompt import Confirm
5
- from substrateinterface.exceptions import SubstrateRequestException
5
+ from async_substrate_interface.errors import SubstrateRequestException
6
6
 
7
7
  from bittensor_cli.src import NETWORK_EXPLORER_MAP
8
8
  from bittensor_cli.src.bittensor.balances import Balance
@@ -64,14 +64,14 @@ async def transfer_extrinsic(
64
64
  call=call, keypair=wallet.coldkeypub
65
65
  )
66
66
  except SubstrateRequestException as e:
67
- payment_info = {"partialFee": int(2e7)} # assume 0.02 Tao
67
+ payment_info = {"partial_fee": int(2e7)} # assume 0.02 Tao
68
68
  err_console.print(
69
69
  f":cross_mark: [red]Failed to get payment info[/red]:[bold white]\n"
70
70
  f" {format_error_message(e)}[/bold white]\n"
71
71
  f" Defaulting to default transfer fee: {payment_info['partialFee']}"
72
72
  )
73
73
 
74
- return Balance.from_rao(payment_info["partialFee"])
74
+ return Balance.from_rao(payment_info["partial_fee"])
75
75
 
76
76
  async def do_transfer() -> tuple[bool, str, str]:
77
77
  """
@@ -101,11 +101,7 @@ async def transfer_extrinsic(
101
101
  block_hash_ = response.block_hash
102
102
  return True, block_hash_, ""
103
103
  else:
104
- return (
105
- False,
106
- "",
107
- format_error_message(await response.error_message),
108
- )
104
+ return False, "", format_error_message(await response.error_message)
109
105
 
110
106
  # Validate destination address.
111
107
  if not is_valid_bittensor_address_or_public_key(destination):
@@ -126,13 +122,12 @@ async def transfer_extrinsic(
126
122
  # check existential deposit and fee
127
123
  print_verbose("Fetching existential and fee", status)
128
124
  block_hash = await subtensor.substrate.get_chain_head()
129
- account_balance_, existential_deposit = await asyncio.gather(
125
+ account_balance, existential_deposit = await asyncio.gather(
130
126
  subtensor.get_balance(
131
127
  wallet.coldkeypub.ss58_address, block_hash=block_hash
132
128
  ),
133
129
  subtensor.get_existential_deposit(block_hash=block_hash),
134
130
  )
135
- account_balance = account_balance_[wallet.coldkeypub.ss58_address]
136
131
  fee = await get_transfer_fee()
137
132
 
138
133
  if not keep_alive:
@@ -194,7 +189,7 @@ async def transfer_extrinsic(
194
189
  )
195
190
  console.print(
196
191
  f"Balance:\n"
197
- f" [blue]{account_balance}[/blue] :arrow_right: [green]{new_balance[wallet.coldkeypub.ss58_address]}[/green]"
192
+ f" [blue]{account_balance}[/blue] :arrow_right: [green]{new_balance}[/green]"
198
193
  )
199
194
  return True
200
195
 
@@ -3,7 +3,7 @@ import asyncio
3
3
  import numpy as np
4
4
  from numpy.typing import NDArray
5
5
 
6
- from bittensor_cli.src.bittensor.chain_data import NeuronInfo
6
+ from bittensor_cli.src.bittensor.chain_data import NeuronInfo, SubnetState
7
7
  from bittensor_cli.src.bittensor.subtensor_interface import SubtensorInterface
8
8
  from bittensor_cli.src.bittensor.utils import (
9
9
  convert_root_weight_uids_and_vals_to_tensor,
@@ -18,6 +18,7 @@ class MiniGraph:
18
18
  netuid: int,
19
19
  neurons: list[NeuronInfo],
20
20
  subtensor: "SubtensorInterface",
21
+ subnet_state: "SubnetState",
21
22
  block: int,
22
23
  ):
23
24
  self.neurons = neurons
@@ -62,12 +63,14 @@ class MiniGraph:
62
63
  self.validator_trust = self._create_tensor(
63
64
  [neuron.validator_trust for neuron in self.neurons], dtype=np.float32
64
65
  )
65
- self.total_stake = self._create_tensor(
66
- [neuron.total_stake.tao for neuron in self.neurons], dtype=np.float32
67
- )
68
- self.stake = self._create_tensor(
69
- [neuron.stake for neuron in self.neurons], dtype=np.float32
66
+
67
+ # Fetch stakes from subnet_state until we get updated data in NeuronInfo
68
+ global_stake_list, local_stake_list, stake_weights_list = self._process_stakes(
69
+ neurons, subnet_state
70
70
  )
71
+ self.global_stake = self._create_tensor(global_stake_list, dtype=np.float32)
72
+ self.local_stake = self._create_tensor(local_stake_list, dtype=np.float32)
73
+ self.stake_weights = self._create_tensor(stake_weights_list, dtype=np.float32)
71
74
 
72
75
  async def __aenter__(self):
73
76
  if not self.weights:
@@ -120,6 +123,41 @@ class MiniGraph:
120
123
  [neuron.bonds for neuron in self.neurons], "bonds"
121
124
  )
122
125
 
126
+ def _process_stakes(
127
+ self,
128
+ neurons: list[NeuronInfo],
129
+ subnet_state: SubnetState,
130
+ ) -> tuple[list[float], list[float], list[float]]:
131
+ """
132
+ Processes the global_stake, local_stake, and stake_weights based on the neuron's hotkey.
133
+
134
+ Args:
135
+ neurons (List[NeuronInfo]): List of neurons.
136
+ subnet_state (SubnetState): The subnet state containing stake information.
137
+
138
+ Returns:
139
+ tuple[list[float], list[float], list[float]]: Lists of global_stake, local_stake, and stake_weights.
140
+ """
141
+ global_stake_list = []
142
+ local_stake_list = []
143
+ stake_weights_list = []
144
+ hotkey_to_index = {
145
+ hotkey: idx for idx, hotkey in enumerate(subnet_state.hotkeys)
146
+ }
147
+
148
+ for neuron in neurons:
149
+ idx = hotkey_to_index.get(neuron.hotkey)
150
+ if idx is not None:
151
+ global_stake_list.append(subnet_state.global_stake[idx].tao)
152
+ local_stake_list.append(subnet_state.local_stake[idx].tao)
153
+ stake_weights_list.append(subnet_state.stake_weight[idx])
154
+ else:
155
+ global_stake_list.append(0.0)
156
+ local_stake_list.append(0.0)
157
+ stake_weights_list.append(0.0)
158
+
159
+ return global_stake_list, local_stake_list, stake_weights_list
160
+
123
161
  def _process_weights_or_bonds(self, data, attribute: str) -> NDArray:
124
162
  """
125
163
  Processes the raw weights or bonds data and converts it into a structured tensor format. This method handles
@@ -177,7 +215,7 @@ class MiniGraph:
177
215
  """
178
216
 
179
217
  async def get_total_subnets():
180
- _result = await self.subtensor.substrate.query(
218
+ _result = await self.subtensor.query(
181
219
  module="SubtensorModule",
182
220
  storage_function="TotalNetworks",
183
221
  params=[],
@@ -186,7 +224,7 @@ class MiniGraph:
186
224
  return _result
187
225
 
188
226
  async def get_subnets():
189
- _result = await self.subtensor.substrate.query(
227
+ _result = await self.subtensor.query(
190
228
  module="SubtensorModule",
191
229
  storage_function="TotalNetworks",
192
230
  )