bittensor-cli 8.4.3__py3-none-any.whl → 9.0.0rc2__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 (30) hide show
  1. bittensor_cli/__init__.py +2 -2
  2. bittensor_cli/cli.py +1508 -1385
  3. bittensor_cli/src/__init__.py +627 -197
  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 +161 -47
  7. bittensor_cli/src/bittensor/extrinsics/root.py +14 -8
  8. bittensor_cli/src/bittensor/extrinsics/transfer.py +14 -21
  9. bittensor_cli/src/bittensor/minigraph.py +46 -8
  10. bittensor_cli/src/bittensor/subtensor_interface.py +572 -253
  11. bittensor_cli/src/bittensor/utils.py +326 -75
  12. bittensor_cli/src/commands/stake/__init__.py +154 -0
  13. bittensor_cli/src/commands/stake/children_hotkeys.py +121 -87
  14. bittensor_cli/src/commands/stake/move.py +1000 -0
  15. bittensor_cli/src/commands/stake/stake.py +1637 -1264
  16. bittensor_cli/src/commands/subnets/__init__.py +0 -0
  17. bittensor_cli/src/commands/subnets/price.py +867 -0
  18. bittensor_cli/src/commands/subnets/subnets.py +2055 -0
  19. bittensor_cli/src/commands/sudo.py +529 -26
  20. bittensor_cli/src/commands/wallets.py +234 -544
  21. bittensor_cli/src/commands/weights.py +15 -11
  22. {bittensor_cli-8.4.3.dist-info → bittensor_cli-9.0.0rc2.dist-info}/METADATA +7 -4
  23. bittensor_cli-9.0.0rc2.dist-info/RECORD +32 -0
  24. bittensor_cli/src/bittensor/async_substrate_interface.py +0 -2748
  25. bittensor_cli/src/commands/root.py +0 -1752
  26. bittensor_cli/src/commands/subnets.py +0 -897
  27. bittensor_cli-8.4.3.dist-info/RECORD +0 -31
  28. {bittensor_cli-8.4.3.dist-info → bittensor_cli-9.0.0rc2.dist-info}/WHEEL +0 -0
  29. {bittensor_cli-8.4.3.dist-info → bittensor_cli-9.0.0rc2.dist-info}/entry_points.txt +0 -0
  30. {bittensor_cli-8.4.3.dist-info → bittensor_cli-9.0.0rc2.dist-info}/top_level.txt +0 -0
@@ -2,10 +2,11 @@ import asyncio
2
2
  from typing import Optional
3
3
 
4
4
  from bittensor_wallet import Wallet
5
+ from bittensor_wallet.errors import KeyFileError
5
6
  from rich.prompt import Confirm, Prompt, IntPrompt
6
7
  from rich.table import Table
7
8
  from rich.text import Text
8
- from substrateinterface.exceptions import SubstrateRequestException
9
+ from async_substrate_interface.errors import SubstrateRequestException
9
10
 
10
11
  from bittensor_cli.src.bittensor.balances import Balance
11
12
  from bittensor_cli.src.bittensor.subtensor_interface import SubtensorInterface
@@ -18,10 +19,36 @@ from bittensor_cli.src.bittensor.utils import (
18
19
  u64_to_float,
19
20
  is_valid_ss58_address,
20
21
  format_error_message,
21
- unlock_key,
22
22
  )
23
23
 
24
24
 
25
+ async def get_childkey_completion_block(
26
+ subtensor: SubtensorInterface, netuid: int
27
+ ) -> tuple[int, int]:
28
+ """
29
+ Calculates the block at which the childkey set request will complete
30
+ """
31
+ blocks_since_last_step_query = subtensor.query(
32
+ "SubtensorModule",
33
+ "BlocksSinceLastStep",
34
+ params=[netuid],
35
+ )
36
+ tempo_query = subtensor.get_hyperparameter(
37
+ param_name="Tempo",
38
+ netuid=netuid,
39
+ )
40
+ block_number, blocks_since_last_step, tempo = await asyncio.gather(
41
+ subtensor.substrate.get_block_number(),
42
+ blocks_since_last_step_query,
43
+ tempo_query,
44
+ )
45
+ cooldown = block_number + 1
46
+ blocks_left_in_tempo = tempo - blocks_since_last_step
47
+ next_tempo = block_number + blocks_left_in_tempo
48
+ next_epoch_after_cooldown = (cooldown - next_tempo) % tempo + cooldown
49
+ return block_number, next_epoch_after_cooldown
50
+
51
+
25
52
  async def set_children_extrinsic(
26
53
  subtensor: "SubtensorInterface",
27
54
  wallet: Wallet,
@@ -72,8 +99,10 @@ async def set_children_extrinsic(
72
99
  return False, "Operation Cancelled"
73
100
 
74
101
  # Decrypt coldkey.
75
- if not (unlock_status := unlock_key(wallet, print_out=False)).success:
76
- return False, unlock_status.message
102
+ try:
103
+ wallet.unlock_coldkey()
104
+ except KeyFileError:
105
+ return False, "There was an error unlocking your coldkey."
77
106
 
78
107
  with console.status(
79
108
  f":satellite: {operation} on [white]{subtensor.network}[/white] ..."
@@ -156,8 +185,10 @@ async def set_childkey_take_extrinsic(
156
185
  return False, "Operation Cancelled"
157
186
 
158
187
  # Decrypt coldkey.
159
- if not (unlock_status := unlock_key(wallet, print_out=False)).success:
160
- return False, unlock_status.message
188
+ try:
189
+ wallet.unlock_coldkey()
190
+ except KeyFileError:
191
+ return False, "There was an error unlocking your coldkey."
161
192
 
162
193
  with console.status(
163
194
  f":satellite: Setting childkey take on [white]{subtensor.network}[/white] ..."
@@ -208,7 +239,7 @@ async def set_childkey_take_extrinsic(
208
239
  except SubstrateRequestException as e:
209
240
  return (
210
241
  False,
211
- f"Exception occurred while setting childkey take: {format_error_message(e)}",
242
+ f"Exception occurred while setting childkey take: {format_error_message(e, subtensor.substrate)}",
212
243
  )
213
244
 
214
245
 
@@ -223,16 +254,18 @@ async def get_childkey_take(subtensor, hotkey: str, netuid: int) -> Optional[int
223
254
  - Optional[float]: The value of the "ChildkeyTake" if found, or None if any error occurs.
224
255
  """
225
256
  try:
226
- childkey_take_ = await subtensor.substrate.query(
257
+ childkey_take_ = await subtensor.query(
227
258
  module="SubtensorModule",
228
259
  storage_function="ChildkeyTake",
229
260
  params=[hotkey, netuid],
230
261
  )
231
262
  if childkey_take_:
232
- return int(childkey_take_)
263
+ return int(childkey_take_.value)
233
264
 
234
265
  except SubstrateRequestException as e:
235
- err_console.print(f"Error querying ChildKeys: {format_error_message(e)}")
266
+ err_console.print(
267
+ f"Error querying ChildKeys: {format_error_message(e, subtensor.substrate)}"
268
+ )
236
269
  return None
237
270
 
238
271
 
@@ -264,6 +297,7 @@ def prepare_child_proportions(children_with_proportions):
264
297
  async def get_children(
265
298
  wallet: Wallet, subtensor: "SubtensorInterface", netuid: Optional[int] = None
266
299
  ):
300
+ # TODO rao asks separately for the hotkey from the user, should we do this, or the way we do it now?
267
301
  """
268
302
  Retrieves the child hotkeys for the specified wallet.
269
303
 
@@ -281,35 +315,7 @@ async def get_children(
281
315
  - If netuid is not specified, generates and prints a summary table of all child hotkeys across all subnets.
282
316
  """
283
317
 
284
- async def get_total_stake_for_hk(hotkey: str, parent: bool = False):
285
- """
286
- Fetches and displays the total stake for a specified hotkey from the Subtensor blockchain network.
287
- If `parent` is True, it prints the hotkey and its corresponding stake.
288
-
289
- Parameters:
290
- - hotkey (str): The hotkey for which the stake needs to be fetched.
291
- - parent (bool, optional): A flag to indicate whether the hotkey is the parent key. Defaults to False.
292
-
293
- Returns:
294
- - Balance: The total stake associated with the specified hotkey.
295
- """
296
- _result = await subtensor.substrate.query(
297
- module="SubtensorModule",
298
- storage_function="TotalHotkeyStake",
299
- params=[hotkey],
300
- reuse_block_hash=True,
301
- )
302
- stake = Balance.from_rao(_result) if _result is not None else Balance(0)
303
- if parent:
304
- console.print(
305
- f"\nYour Hotkey: [bright_magenta]{hotkey}[/bright_magenta] | Total Stake: [dark_orange]{stake}t[/dark_orange]\n",
306
- end="",
307
- no_wrap=True,
308
- )
309
-
310
- return stake
311
-
312
- async def get_take(child: tuple) -> float:
318
+ async def get_take(child: tuple, netuid__: int) -> float:
313
319
  """
314
320
  Get the take value for a given subtensor, hotkey, and netuid.
315
321
 
@@ -320,7 +326,7 @@ async def get_children(
320
326
  """
321
327
  child_hotkey = child[1]
322
328
  take_u16 = await get_childkey_take(
323
- subtensor=subtensor, hotkey=child_hotkey, netuid=netuid
329
+ subtensor=subtensor, hotkey=child_hotkey, netuid=netuid__
324
330
  )
325
331
  if take_u16:
326
332
  return u16_to_float(take_u16)
@@ -329,7 +335,7 @@ async def get_children(
329
335
 
330
336
  async def _render_table(
331
337
  parent_hotkey: str,
332
- netuid_children_tuples: list[tuple[int, list[tuple[int, str]]]],
338
+ netuid_children_: list[tuple[int, list[tuple[int, str]]]],
333
339
  ):
334
340
  """
335
341
  Retrieves and renders children hotkeys and their details for a given parent hotkey.
@@ -352,10 +358,11 @@ async def get_children(
352
358
  "Current Stake Weight", style="bold red", no_wrap=True, justify="right"
353
359
  )
354
360
 
355
- if not netuid_children_tuples:
361
+ if not netuid_children_:
356
362
  console.print(table)
357
363
  console.print(
358
- f"[bold red]There are currently no child hotkeys with parent hotkey: {wallet.name} ({parent_hotkey}).[/bold red]"
364
+ f"[bold red]There are currently no child hotkeys with parent hotkey: "
365
+ f"{wallet.name} | {wallet.hotkey_str} ({parent_hotkey}).[/bold red]"
359
366
  )
360
367
  return
361
368
 
@@ -363,48 +370,64 @@ async def get_children(
363
370
  total_proportion = 0
364
371
  total_stake_weight = 0
365
372
 
366
- netuid_children_tuples.sort(
367
- key=lambda x: x[0]
368
- ) # Sort by netuid in ascending order
373
+ netuid_children_.sort(key=lambda x: x[0]) # Sort by netuid in ascending order
374
+ unique_keys = set(
375
+ [parent_hotkey]
376
+ + [s for _, child_list in netuid_children_ for _, s in child_list]
377
+ )
378
+ hotkey_stake_dict = await subtensor.get_total_stake_for_hotkey(
379
+ *unique_keys,
380
+ netuids=[n[0] for n in netuid_children_],
381
+ )
382
+ parent_total = sum(hotkey_stake_dict[parent_hotkey].values())
383
+ insert_text = (
384
+ " "
385
+ if netuid is None
386
+ else f" on netuids: {', '.join(str(n[0]) for n in netuid_children_)} "
387
+ )
388
+ console.print(
389
+ f"The total stake of parent hotkey '{parent_hotkey}'{insert_text}is {parent_total}."
390
+ )
369
391
 
370
- for index, (netuid, children_) in enumerate(netuid_children_tuples):
392
+ for index, (netuid_, children_) in enumerate(netuid_children_):
371
393
  # calculate totals
372
394
  total_proportion_per_netuid = 0
373
395
  total_stake_weight_per_netuid = 0
374
- avg_take_per_netuid = 0
396
+ avg_take_per_netuid = 0.0
375
397
 
376
- hotkey_stake_dict = await subtensor.get_total_stake_for_hotkey(
377
- parent_hotkey
378
- )
379
- hotkey_stake = hotkey_stake_dict.get(parent_hotkey, Balance(0))
398
+ hotkey_stake: dict[int, Balance] = hotkey_stake_dict[parent_hotkey]
380
399
 
381
400
  children_info = []
382
- child_stakes = await asyncio.gather(
383
- *[get_total_stake_for_hk(c[1]) for c in children_]
401
+ child_takes = await asyncio.gather(
402
+ *[get_take(c, netuid_) for c in children_]
384
403
  )
385
- child_takes = await asyncio.gather(*[get_take(c) for c in children_])
386
- for child, child_stake, child_take in zip(
387
- children_, child_stakes, child_takes
388
- ):
404
+ for child, child_take in zip(children_, child_takes):
389
405
  proportion = child[0]
390
406
  child_hotkey = child[1]
391
407
 
392
408
  # add to totals
393
409
  avg_take_per_netuid += child_take
394
410
 
395
- proportion = u64_to_float(proportion)
411
+ converted_proportion = u64_to_float(proportion)
396
412
 
397
413
  children_info.append(
398
- (proportion, child_hotkey, child_stake, child_take)
414
+ (
415
+ converted_proportion,
416
+ child_hotkey,
417
+ hotkey_stake_dict[child_hotkey][netuid_],
418
+ child_take,
419
+ )
399
420
  )
400
421
 
401
422
  children_info.sort(
402
423
  key=lambda x: x[0], reverse=True
403
424
  ) # sorting by proportion (highest first)
404
425
 
405
- for proportion, hotkey, stake, child_take in children_info:
406
- proportion_percent = proportion * 100 # Proportion in percent
407
- proportion_tao = hotkey_stake.tao * proportion # Proportion in TAO
426
+ for proportion_, hotkey, stake, child_take in children_info:
427
+ proportion_percent = proportion_ * 100 # Proportion in percent
428
+ proportion_tao = (
429
+ hotkey_stake[netuid_].tao * proportion_
430
+ ) # Proportion in TAO
408
431
 
409
432
  total_proportion_per_netuid += proportion_percent
410
433
 
@@ -414,9 +437,9 @@ async def get_children(
414
437
  total_stake_weight_per_netuid += stake_weight
415
438
  take_str = f"{child_take * 100:.3f}%"
416
439
 
417
- hotkey = Text(hotkey, style="italic red" if proportion == 0 else "")
440
+ hotkey = Text(hotkey, style="italic red" if proportion_ == 0 else "")
418
441
  table.add_row(
419
- str(netuid),
442
+ str(netuid_),
420
443
  hotkey,
421
444
  proportion_str,
422
445
  take_str,
@@ -440,7 +463,7 @@ async def get_children(
440
463
  total_stake_weight += total_stake_weight_per_netuid
441
464
 
442
465
  # Add a dividing line if there are more than one netuid
443
- if len(netuid_children_tuples) > 1:
466
+ if len(netuid_children_) > 1:
444
467
  table.add_section()
445
468
 
446
469
  console.print(table)
@@ -449,17 +472,16 @@ async def get_children(
449
472
  if netuid is None:
450
473
  # get all netuids
451
474
  netuids = await subtensor.get_all_subnet_netuids()
452
- await get_total_stake_for_hk(wallet.hotkey.ss58_address, True)
453
475
  netuid_children_tuples = []
454
- for netuid in netuids:
476
+ for netuid_ in netuids:
455
477
  success, children, err_mg = await subtensor.get_children(
456
- wallet.hotkey.ss58_address, netuid
478
+ wallet.hotkey.ss58_address, netuid_
457
479
  )
458
480
  if children:
459
- netuid_children_tuples.append((netuid, children))
481
+ netuid_children_tuples.append((netuid_, children))
460
482
  if not success:
461
483
  err_console.print(
462
- f"Failed to get children from subtensor {netuid}: {err_mg}"
484
+ f"Failed to get children from subtensor {netuid_}: {err_mg}"
463
485
  )
464
486
  await _render_table(wallet.hotkey.ss58_address, netuid_children_tuples)
465
487
  else:
@@ -468,7 +490,6 @@ async def get_children(
468
490
  )
469
491
  if not success:
470
492
  err_console.print(f"Failed to get children from subtensor: {err_mg}")
471
- await get_total_stake_for_hk(wallet.hotkey.ss58_address, True)
472
493
  if children:
473
494
  netuid_children_tuples = [(netuid, children)]
474
495
  await _render_table(wallet.hotkey.ss58_address, netuid_children_tuples)
@@ -481,13 +502,15 @@ async def set_children(
481
502
  subtensor: "SubtensorInterface",
482
503
  children: list[str],
483
504
  proportions: list[float],
484
- netuid: Optional[int] = None,
505
+ netuid: Optional[int],
485
506
  wait_for_inclusion: bool = True,
486
507
  wait_for_finalization: bool = True,
487
508
  prompt: bool = True,
488
509
  ):
489
510
  """Set children hotkeys."""
490
511
  # Validate children SS58 addresses
512
+ # TODO check to see if this should be allowed to be specified by user instead of pulling from wallet
513
+ hotkey = wallet.hotkey.ss58_address
491
514
  for child in children:
492
515
  if not is_valid_ss58_address(child):
493
516
  err_console.print(f":cross_mark:[red] Invalid SS58 address: {child}[/red]")
@@ -502,14 +525,13 @@ async def set_children(
502
525
  f"Invalid proportion: The sum of all proportions cannot be greater than 1. "
503
526
  f"Proposed sum of proportions is {total_proposed}."
504
527
  )
505
-
506
528
  children_with_proportions = list(zip(proportions, children))
507
- if netuid:
529
+ if netuid is not None:
508
530
  success, message = await set_children_extrinsic(
509
531
  subtensor=subtensor,
510
532
  wallet=wallet,
511
533
  netuid=netuid,
512
- hotkey=wallet.hotkey.ss58_address,
534
+ hotkey=hotkey,
513
535
  children_with_proportions=children_with_proportions,
514
536
  prompt=prompt,
515
537
  wait_for_inclusion=wait_for_inclusion,
@@ -518,8 +540,13 @@ async def set_children(
518
540
  # Result
519
541
  if success:
520
542
  if wait_for_inclusion and wait_for_finalization:
521
- console.print("New Status:")
522
- await get_children(wallet, subtensor, netuid)
543
+ current_block, completion_block = await get_childkey_completion_block(
544
+ subtensor, netuid
545
+ )
546
+ console.print(
547
+ f"Your childkey request has been submitted. It will be completed around block {completion_block}. "
548
+ f"The current block is {current_block}"
549
+ )
523
550
  console.print(
524
551
  ":white_heavy_check_mark: [green]Set children hotkeys.[/green]"
525
552
  )
@@ -530,20 +557,27 @@ async def set_children(
530
557
  else:
531
558
  # set children on all subnets that parent is registered on
532
559
  netuids = await subtensor.get_all_subnet_netuids()
533
- for netuid in netuids:
534
- if netuid == 0: # dont include root network
560
+ for netuid_ in netuids:
561
+ if netuid_ == 0: # dont include root network
535
562
  continue
536
- console.print(f"Setting children on netuid {netuid}.")
563
+ console.print(f"Setting children on netuid {netuid_}.")
537
564
  await set_children_extrinsic(
538
565
  subtensor=subtensor,
539
566
  wallet=wallet,
540
- netuid=netuid,
541
- hotkey=wallet.hotkey.ss58_address,
567
+ netuid=netuid_,
568
+ hotkey=hotkey,
542
569
  children_with_proportions=children_with_proportions,
543
570
  prompt=prompt,
544
571
  wait_for_inclusion=True,
545
572
  wait_for_finalization=False,
546
573
  )
574
+ current_block, completion_block = await get_childkey_completion_block(
575
+ subtensor, netuid_
576
+ )
577
+ console.print(
578
+ f"Your childkey request for netuid {netuid_} has been submitted. It will be completed around "
579
+ f"block {completion_block}. The current block is {current_block}."
580
+ )
547
581
  console.print(
548
582
  ":white_heavy_check_mark: [green]Sent set children request for all subnets.[/green]"
549
583
  )
@@ -555,8 +589,8 @@ async def revoke_children(
555
589
  netuid: Optional[int] = None,
556
590
  wait_for_inclusion: bool = True,
557
591
  wait_for_finalization: bool = True,
558
- prompt: bool = True,
559
592
  ):
593
+ # TODO seek clarification on use of asking hotkey vs how we do it now
560
594
  """
561
595
  Revokes the children hotkeys associated with a given network identifier (netuid).
562
596
  """
@@ -567,7 +601,7 @@ async def revoke_children(
567
601
  netuid=netuid,
568
602
  hotkey=wallet.hotkey.ss58_address,
569
603
  children_with_proportions=[],
570
- prompt=prompt,
604
+ prompt=True,
571
605
  wait_for_inclusion=wait_for_inclusion,
572
606
  wait_for_finalization=wait_for_finalization,
573
607
  )
@@ -596,7 +630,7 @@ async def revoke_children(
596
630
  netuid=netuid,
597
631
  hotkey=wallet.hotkey.ss58_address,
598
632
  children_with_proportions=[],
599
- prompt=prompt,
633
+ prompt=False,
600
634
  wait_for_inclusion=True,
601
635
  wait_for_finalization=False,
602
636
  )
@@ -756,7 +790,7 @@ async def childkey_take(
756
790
  netuid=netuid,
757
791
  hotkey=wallet.hotkey.ss58_address,
758
792
  take=take,
759
- prompt=prompt,
793
+ prompt=False,
760
794
  wait_for_inclusion=True,
761
795
  wait_for_finalization=False,
762
796
  )