Skip to content

Commit 98d0af6

Browse files
author
opendansor
authored
Merge pull request #2071 from opentensor/feature/opendansor/child_hotkeys
Child Hotkeys
2 parents 8c6909c + 36c42a0 commit 98d0af6

File tree

14 files changed

+1047
-80
lines changed

14 files changed

+1047
-80
lines changed

bittensor/__init__.py

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -205,19 +205,6 @@ def debug(on: bool = True):
205205
},
206206
},
207207
},
208-
"ValidatorIPRuntimeApi": {
209-
"methods": {
210-
"get_associated_validator_ip_info_for_subnet": {
211-
"params": [
212-
{
213-
"name": "netuid",
214-
"type": "u16",
215-
},
216-
],
217-
"type": "Vec<u8>",
218-
},
219-
},
220-
},
221208
"SubnetInfoRuntimeApi": {
222209
"methods": {
223210
"get_subnet_hyperparams": {
@@ -323,7 +310,6 @@ def debug(on: bool = True):
323310
strtobool,
324311
strtobool_with_default,
325312
get_explorer_root_url_by_network_from_map,
326-
get_explorer_root_url_by_network_from_map,
327313
get_explorer_url_for_network,
328314
ss58_address_to_bytes,
329315
U16_NORMALIZED_FLOAT,

bittensor/cli.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,9 @@
7070
CommitWeightCommand,
7171
RevealWeightCommand,
7272
CheckColdKeySwapCommand,
73+
SetChildrenCommand,
74+
GetChildrenCommand,
75+
RevokeChildrenCommand,
7376
)
7477

7578
# Create a console instance for CLI display.
@@ -164,11 +167,14 @@
164167
"stake": {
165168
"name": "stake",
166169
"aliases": ["st", "stakes"],
167-
"help": "Commands for staking and removing stake from hotkey accounts.",
170+
"help": "Commands for staking and removing stake and setting child hotkey accounts.",
168171
"commands": {
169172
"show": StakeShow,
170173
"add": StakeCommand,
171174
"remove": UnStakeCommand,
175+
"get_children": GetChildrenCommand,
176+
"set_children": SetChildrenCommand,
177+
"revoke_children": RevokeChildrenCommand,
172178
},
173179
},
174180
"weights": {

bittensor/commands/__init__.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,13 @@
6262
}
6363
)
6464

65-
from .stake import StakeCommand, StakeShow
66-
from .unstake import UnStakeCommand
65+
from .stake import (
66+
StakeCommand,
67+
StakeShow,
68+
SetChildrenCommand,
69+
GetChildrenCommand,
70+
)
71+
from .unstake import UnStakeCommand, RevokeChildrenCommand
6772
from .overview import OverviewCommand
6873
from .register import (
6974
PowRegisterCommand,

bittensor/commands/stake.py

Lines changed: 302 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,12 @@
1818
import argparse
1919
import os
2020
import sys
21+
import re
2122
from typing import List, Union, Optional, Dict, Tuple
2223

2324
from rich.prompt import Confirm, Prompt
2425
from rich.table import Table
26+
from rich.console import Console
2527
from tqdm import tqdm
2628

2729
import bittensor
@@ -31,7 +33,8 @@
3133
get_delegates_details,
3234
DelegatesDetails,
3335
)
34-
from . import defaults
36+
from . import defaults # type: ignore
37+
from ..utils import wallet_utils
3538

3639
console = bittensor.__console__
3740

@@ -566,3 +569,301 @@ def add_args(parser: argparse.ArgumentParser):
566569

567570
bittensor.wallet.add_args(list_parser)
568571
bittensor.subtensor.add_args(list_parser)
572+
573+
574+
class SetChildrenCommand:
575+
"""
576+
Executes the ``set_children`` command to add children hotkeys on a specified subnet on the Bittensor network.
577+
578+
This command is used to delegate authority to different hotkeys, securing their position and influence on the subnet.
579+
580+
Usage:
581+
Users can specify the amount or 'proportion' to delegate to child hotkeys (``SS58`` address),
582+
the user needs to have sufficient authority to make this call, and the sum of proportions cannot be greater than 1.
583+
584+
The command prompts for confirmation before executing the set_children operation.
585+
586+
Example usage::
587+
588+
btcli stake set_children --children <child_hotkey>,<child_hotkey> --hotkey <parent_hotkey> --netuid 1 --proportions 0.3,0.3
589+
590+
Note:
591+
This command is critical for users who wish to delegate children hotkeys among different neurons (hotkeys) on the network.
592+
It allows for a strategic allocation of authority to enhance network participation and influence.
593+
"""
594+
595+
@staticmethod
596+
def run(cli: "bittensor.cli"):
597+
"""Set children hotkeys."""
598+
try:
599+
subtensor: "bittensor.subtensor" = bittensor.subtensor(
600+
config=cli.config, log_verbose=False
601+
)
602+
SetChildrenCommand._run(cli, subtensor)
603+
finally:
604+
if "subtensor" in locals():
605+
subtensor.close()
606+
bittensor.logging.debug("closing subtensor connection")
607+
608+
@staticmethod
609+
def _run(cli: "bittensor.cli", subtensor: "bittensor.subtensor"):
610+
wallet = bittensor.wallet(config=cli.config)
611+
612+
# Get values if not set.
613+
if not cli.config.is_set("netuid"):
614+
cli.config.netuid = int(Prompt.ask("Enter netuid"))
615+
616+
if not cli.config.is_set("hotkey"):
617+
cli.config.hotkey = Prompt.ask("Enter parent hotkey (ss58)")
618+
619+
children = GetChildrenCommand.run(cli)
620+
621+
if not cli.config.is_set("children"):
622+
cli.config.children = Prompt.ask(
623+
"Enter children hotkey (ss58) as comma-separated values"
624+
)
625+
626+
if not cli.config.is_set("proportions"):
627+
cli.config.proportions = Prompt.ask(
628+
"Enter proportions for children as comma-separated values (sum less than 1)"
629+
)
630+
631+
# Parse from strings
632+
netuid = cli.config.netuid
633+
634+
# extract proportions and child addresses from cli input
635+
proportions = [float(x) for x in re.split(r"[ ,]+", cli.config.proportions)]
636+
children = [str(x) for x in re.split(r"[ ,]+", cli.config.children)]
637+
638+
# Validate children SS58 addresses
639+
for child in children:
640+
if not wallet_utils.is_valid_ss58_address(child):
641+
console.print(f":cross_mark:[red] Invalid SS58 address: {child}[/red]")
642+
return
643+
644+
total_proposed = sum(proportions)
645+
if total_proposed > 1:
646+
raise ValueError(
647+
f"Invalid proportion: The sum of all proportions cannot be greater than 1. Proposed sum of proportions is {total_proposed}."
648+
)
649+
650+
children_with_proportions = list(zip(proportions, children))
651+
652+
success, message = subtensor.set_children(
653+
wallet=wallet,
654+
netuid=netuid,
655+
hotkey=cli.config.hotkey,
656+
children_with_proportions=children_with_proportions,
657+
wait_for_inclusion=cli.config.wait_for_inclusion,
658+
wait_for_finalization=cli.config.wait_for_finalization,
659+
prompt=cli.config.prompt,
660+
)
661+
662+
# Result
663+
if success:
664+
console.print(
665+
":white_heavy_check_mark: [green]Set children hotkeys.[/green]"
666+
)
667+
else:
668+
console.print(
669+
f":cross_mark:[red] Unable to set children hotkeys.[/red] {message}"
670+
)
671+
672+
@staticmethod
673+
def check_config(config: "bittensor.config"):
674+
if not config.is_set("wallet.name") and not config.no_prompt:
675+
wallet_name = Prompt.ask("Enter wallet name", default=defaults.wallet.name)
676+
config.wallet.name = str(wallet_name)
677+
if not config.is_set("wallet.hotkey") and not config.no_prompt:
678+
hotkey = Prompt.ask("Enter hotkey name", default=defaults.wallet.hotkey)
679+
config.wallet.hotkey = str(hotkey)
680+
681+
@staticmethod
682+
def add_args(parser: argparse.ArgumentParser):
683+
set_children_parser = parser.add_parser(
684+
"set_children", help="""Set multiple children hotkeys."""
685+
)
686+
set_children_parser.add_argument(
687+
"--netuid", dest="netuid", type=int, required=False
688+
)
689+
set_children_parser.add_argument(
690+
"--children", dest="children", type=str, required=False
691+
)
692+
set_children_parser.add_argument(
693+
"--hotkey", dest="hotkey", type=str, required=False
694+
)
695+
set_children_parser.add_argument(
696+
"--proportions", dest="proportions", type=str, required=False
697+
)
698+
set_children_parser.add_argument(
699+
"--wait_for_inclusion",
700+
dest="wait_for_inclusion",
701+
action="store_true",
702+
default=False,
703+
help="""Wait for the transaction to be included in a block.""",
704+
)
705+
set_children_parser.add_argument(
706+
"--wait_for_finalization",
707+
dest="wait_for_finalization",
708+
action="store_true",
709+
default=True,
710+
help="""Wait for the transaction to be finalized.""",
711+
)
712+
set_children_parser.add_argument(
713+
"--prompt",
714+
dest="prompt",
715+
action="store_true",
716+
default=False,
717+
help="""Prompt for confirmation before proceeding.""",
718+
)
719+
bittensor.wallet.add_args(set_children_parser)
720+
bittensor.subtensor.add_args(set_children_parser)
721+
722+
723+
class GetChildrenCommand:
724+
"""
725+
Executes the ``get_children_info`` command to get all child hotkeys on a specified subnet on the Bittensor network.
726+
727+
This command is used to view delegated authority to different hotkeys on the subnet.
728+
729+
Usage:
730+
Users can specify the subnet and see the children and the proportion that is given to them.
731+
732+
The command compiles a table showing:
733+
734+
- ChildHotkey: The hotkey associated with the child.
735+
- ParentHotKey: The hotkey associated with the parent.
736+
- Proportion: The proportion that is assigned to them.
737+
- Expiration: The expiration of the hotkey.
738+
739+
Example usage::
740+
741+
btcli stake get_children --netuid 1
742+
743+
Note:
744+
This command is for users who wish to see child hotkeys among different neurons (hotkeys) on the network.
745+
"""
746+
747+
@staticmethod
748+
def run(cli: "bittensor.cli"):
749+
"""Get children hotkeys."""
750+
try:
751+
subtensor: "bittensor.subtensor" = bittensor.subtensor(
752+
config=cli.config, log_verbose=False
753+
)
754+
return GetChildrenCommand._run(cli, subtensor)
755+
finally:
756+
if "subtensor" in locals():
757+
subtensor.close()
758+
bittensor.logging.debug("closing subtensor connection")
759+
760+
@staticmethod
761+
def _run(cli: "bittensor.cli", subtensor: "bittensor.subtensor"):
762+
# Get values if not set.
763+
if not cli.config.is_set("netuid"):
764+
cli.config.netuid = int(Prompt.ask("Enter netuid"))
765+
766+
# Get values if not set.
767+
if not cli.config.is_set("hotkey"):
768+
cli.config.netuid = Prompt.ask("Enter hotkey")
769+
770+
# Parse from strings
771+
netuid = cli.config.netuid
772+
hotkey = cli.config.hotkey
773+
774+
children = subtensor.get_children(hotkey, netuid)
775+
776+
GetChildrenCommand.render_table(subtensor, hotkey, children, netuid)
777+
778+
return children
779+
780+
@staticmethod
781+
def check_config(config: "bittensor.config"):
782+
if not config.is_set("wallet.name") and not config.no_prompt:
783+
wallet_name = Prompt.ask("Enter wallet name", default=defaults.wallet.name)
784+
config.wallet.name = str(wallet_name)
785+
if not config.is_set("wallet.hotkey") and not config.no_prompt:
786+
hotkey = Prompt.ask("Enter hotkey name", default=defaults.wallet.hotkey)
787+
config.wallet.hotkey = str(hotkey)
788+
789+
@staticmethod
790+
def add_args(parser: argparse.ArgumentParser):
791+
parser = parser.add_parser(
792+
"get_children", help="""Get child hotkeys on subnet."""
793+
)
794+
parser.add_argument("--netuid", dest="netuid", type=int, required=False)
795+
parser.add_argument("--hotkey", dest="hotkey", type=str, required=False)
796+
797+
bittensor.wallet.add_args(parser)
798+
bittensor.subtensor.add_args(parser)
799+
800+
@staticmethod
801+
def render_table(
802+
subtensor: "bittensor.subtensor",
803+
hotkey: str,
804+
children: list[Tuple[int, str]],
805+
netuid: int,
806+
):
807+
console = Console()
808+
809+
# Initialize Rich table for pretty printing
810+
table = Table(
811+
show_header=True,
812+
header_style="bold magenta",
813+
border_style="green",
814+
style="green",
815+
)
816+
817+
# Add columns to the table with specific styles
818+
table.add_column("Index", style="cyan", no_wrap=True, justify="right")
819+
table.add_column("ChildHotkey", style="cyan", no_wrap=True)
820+
table.add_column("Proportion", style="cyan", no_wrap=True, justify="right")
821+
table.add_column("Total Stake", style="cyan", no_wrap=True, justify="right")
822+
823+
if not children:
824+
console.print(table)
825+
826+
command = f"btcli stake set_children --children <child_hotkey> --hotkey <parent_hotkey> --netuid {netuid} --proportion <float>"
827+
console.print(f"There are currently no child hotkeys on subnet {netuid}.")
828+
console.print(
829+
f"To add a child hotkey you can run the command: [white]{command}[/white]"
830+
)
831+
return
832+
833+
console.print("ParentHotKey:", style="cyan", no_wrap=True)
834+
console.print(hotkey)
835+
836+
# calculate totals
837+
total_proportion = 0
838+
total_stake = 0
839+
840+
children_info = []
841+
for child in children:
842+
proportion = child[0]
843+
child_hotkey = child[1]
844+
child_stake = subtensor.get_total_stake_for_hotkey(
845+
ss58_address=child_hotkey
846+
) or Balance(0)
847+
848+
# add to totals
849+
total_proportion += proportion
850+
total_stake += child_stake
851+
852+
children_info.append((proportion, child_hotkey, child_stake))
853+
854+
children_info.sort(
855+
key=lambda x: x[0], reverse=True
856+
) # sorting by proportion (highest first)
857+
858+
# add the children info to the table
859+
for i, (proportion, hotkey, stake) in enumerate(children_info, 1):
860+
table.add_row(
861+
str(i),
862+
hotkey,
863+
str(proportion),
864+
str(stake),
865+
)
866+
867+
# add totals row
868+
table.add_row("", "Total", str(total_proportion), str(total_stake), "")
869+
console.print(table)

0 commit comments

Comments
 (0)