Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Child Hotkeys #2071

Merged
merged 39 commits into from
Aug 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
6dda55b
init commit
opendansor Jun 26, 2024
783392f
Add child singular cli done
opendansor Jun 26, 2024
c8bd350
Set Child Hotkey
opendansor Jun 26, 2024
d2bc588
Set children multiple command.
opendansor Jun 26, 2024
f9d54d0
Remove merge conflict artifacts
opendansor Jun 26, 2024
de50693
Add GetChildrenHotkeysCommand
opendansor Jun 27, 2024
67cedd5
Add RevokeChildHotkey
opendansor Jun 27, 2024
3bc473f
lint
opendansor Jun 27, 2024
b3279ed
Revoke children multiple command
opendansor Jun 27, 2024
b8e2fa5
lint
opendansor Jun 27, 2024
5b2e595
CLI revoke multiple
opendansor Jun 27, 2024
36f7466
lint
opendansor Jun 27, 2024
8766851
Imports
opendansor Jun 27, 2024
f11fe3d
lint
opendansor Jun 27, 2024
156ee56
lint
opendansor Jun 27, 2024
2dcd6f9
imports in init
opendansor Jun 27, 2024
295cd4c
Refactor to follow new pattern
opendansor Jun 29, 2024
e77e688
Merge branch 'staging' into feature/opendansor/child_hotkeys
opendansor Jul 1, 2024
e4db609
U64 for all proportion values
opendansor Jul 1, 2024
79457b3
lint
opendansor Jul 1, 2024
5f6a754
debug
Jul 2, 2024
937f614
Clean up a bit.
opendansor Jul 2, 2024
c34cc8c
Merge pull request #2093 from opentensor/sam/debug_childkey
opendansor Jul 2, 2024
3053276
Clean up a bit.
opendansor Jul 2, 2024
2148dee
u16 to u64
opendansor Jul 3, 2024
2315d8b
un-refactor
opendansor Jul 3, 2024
70655e2
APY + other updates
opendansor Jul 8, 2024
4103cd4
lint
opendansor Jul 8, 2024
98d0768
lint
opendansor Jul 8, 2024
4c3bcbc
Extract Method, and params
opendansor Jul 8, 2024
a3ca5a5
Pr comments
opendansor Jul 10, 2024
26de88c
merge staging into child_hotkeys
opendansor Aug 5, 2024
04bbe9a
Update child hotkeys with new subtensor calls and remove ChildInfo ob…
opendansor Aug 8, 2024
dffb080
ruff
opendansor Aug 9, 2024
c7a95af
Merge branch 'staging' into feature/opendansor/child_hotkeys
opendansor Aug 9, 2024
a18fcd5
update
opendansor Aug 9, 2024
df6564b
update
opendansor Aug 9, 2024
432b503
ruff
opendansor Aug 9, 2024
36c42a0
mypy error
opendansor Aug 9, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 0 additions & 14 deletions bittensor/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -205,19 +205,6 @@ def debug(on: bool = True):
},
},
},
"ValidatorIPRuntimeApi": {
"methods": {
"get_associated_validator_ip_info_for_subnet": {
"params": [
{
"name": "netuid",
"type": "u16",
},
],
"type": "Vec<u8>",
},
},
},
"SubnetInfoRuntimeApi": {
"methods": {
"get_subnet_hyperparams": {
Expand Down Expand Up @@ -323,7 +310,6 @@ def debug(on: bool = True):
strtobool,
strtobool_with_default,
get_explorer_root_url_by_network_from_map,
get_explorer_root_url_by_network_from_map,
get_explorer_url_for_network,
ss58_address_to_bytes,
U16_NORMALIZED_FLOAT,
Expand Down
8 changes: 7 additions & 1 deletion bittensor/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,9 @@
CommitWeightCommand,
RevealWeightCommand,
CheckColdKeySwapCommand,
SetChildrenCommand,
GetChildrenCommand,
RevokeChildrenCommand,
)

# Create a console instance for CLI display.
Expand Down Expand Up @@ -164,11 +167,14 @@
"stake": {
"name": "stake",
"aliases": ["st", "stakes"],
"help": "Commands for staking and removing stake from hotkey accounts.",
"help": "Commands for staking and removing stake and setting child hotkey accounts.",
"commands": {
"show": StakeShow,
"add": StakeCommand,
"remove": UnStakeCommand,
"get_children": GetChildrenCommand,
"set_children": SetChildrenCommand,
"revoke_children": RevokeChildrenCommand,
},
},
"weights": {
Expand Down
9 changes: 7 additions & 2 deletions bittensor/commands/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,13 @@
}
)

from .stake import StakeCommand, StakeShow
from .unstake import UnStakeCommand
from .stake import (
StakeCommand,
StakeShow,
SetChildrenCommand,
GetChildrenCommand,
)
from .unstake import UnStakeCommand, RevokeChildrenCommand
from .overview import OverviewCommand
from .register import (
PowRegisterCommand,
Expand Down
303 changes: 302 additions & 1 deletion bittensor/commands/stake.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,12 @@
import argparse
import os
import sys
import re
from typing import List, Union, Optional, Dict, Tuple

from rich.prompt import Confirm, Prompt
from rich.table import Table
from rich.console import Console
from tqdm import tqdm

import bittensor
Expand All @@ -31,7 +33,8 @@
get_delegates_details,
DelegatesDetails,
)
from . import defaults
from . import defaults # type: ignore
from ..utils import wallet_utils

console = bittensor.__console__

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

bittensor.wallet.add_args(list_parser)
bittensor.subtensor.add_args(list_parser)


class SetChildrenCommand:
"""
Executes the ``set_children`` command to add children hotkeys on a specified subnet on the Bittensor network.

This command is used to delegate authority to different hotkeys, securing their position and influence on the subnet.

Usage:
Users can specify the amount or 'proportion' to delegate to child hotkeys (``SS58`` address),
the user needs to have sufficient authority to make this call, and the sum of proportions cannot be greater than 1.

The command prompts for confirmation before executing the set_children operation.

Example usage::

btcli stake set_children --children <child_hotkey>,<child_hotkey> --hotkey <parent_hotkey> --netuid 1 --proportions 0.3,0.3

Note:
This command is critical for users who wish to delegate children hotkeys among different neurons (hotkeys) on the network.
It allows for a strategic allocation of authority to enhance network participation and influence.
"""

@staticmethod
def run(cli: "bittensor.cli"):
"""Set children hotkeys."""
try:
subtensor: "bittensor.subtensor" = bittensor.subtensor(
config=cli.config, log_verbose=False
)
SetChildrenCommand._run(cli, subtensor)
finally:
if "subtensor" in locals():
subtensor.close()
bittensor.logging.debug("closing subtensor connection")

@staticmethod
def _run(cli: "bittensor.cli", subtensor: "bittensor.subtensor"):
wallet = bittensor.wallet(config=cli.config)

# Get values if not set.
if not cli.config.is_set("netuid"):
cli.config.netuid = int(Prompt.ask("Enter netuid"))

if not cli.config.is_set("hotkey"):
cli.config.hotkey = Prompt.ask("Enter parent hotkey (ss58)")

children = GetChildrenCommand.run(cli)

if not cli.config.is_set("children"):
cli.config.children = Prompt.ask(
"Enter children hotkey (ss58) as comma-separated values"
)

if not cli.config.is_set("proportions"):
cli.config.proportions = Prompt.ask(
"Enter proportions for children as comma-separated values (sum less than 1)"
)

# Parse from strings
netuid = cli.config.netuid

# extract proportions and child addresses from cli input
proportions = [float(x) for x in re.split(r"[ ,]+", cli.config.proportions)]
opendansor marked this conversation as resolved.
Show resolved Hide resolved
children = [str(x) for x in re.split(r"[ ,]+", cli.config.children)]

# Validate children SS58 addresses
for child in children:
if not wallet_utils.is_valid_ss58_address(child):
console.print(f":cross_mark:[red] Invalid SS58 address: {child}[/red]")
return

total_proposed = sum(proportions)
if total_proposed > 1:
raise ValueError(
f"Invalid proportion: The sum of all proportions cannot be greater than 1. Proposed sum of proportions is {total_proposed}."
)

children_with_proportions = list(zip(proportions, children))

success, message = subtensor.set_children(
wallet=wallet,
netuid=netuid,
hotkey=cli.config.hotkey,
children_with_proportions=children_with_proportions,
wait_for_inclusion=cli.config.wait_for_inclusion,
wait_for_finalization=cli.config.wait_for_finalization,
prompt=cli.config.prompt,
)

# Result
if success:
console.print(
":white_heavy_check_mark: [green]Set children hotkeys.[/green]"
)
else:
console.print(
f":cross_mark:[red] Unable to set children hotkeys.[/red] {message}"
)

@staticmethod
def check_config(config: "bittensor.config"):
if not config.is_set("wallet.name") and not config.no_prompt:
wallet_name = Prompt.ask("Enter wallet name", default=defaults.wallet.name)
config.wallet.name = str(wallet_name)
if not config.is_set("wallet.hotkey") and not config.no_prompt:
hotkey = Prompt.ask("Enter hotkey name", default=defaults.wallet.hotkey)
config.wallet.hotkey = str(hotkey)

@staticmethod
def add_args(parser: argparse.ArgumentParser):
set_children_parser = parser.add_parser(
"set_children", help="""Set multiple children hotkeys."""
)
set_children_parser.add_argument(
"--netuid", dest="netuid", type=int, required=False
)
set_children_parser.add_argument(
"--children", dest="children", type=str, required=False
)
set_children_parser.add_argument(
"--hotkey", dest="hotkey", type=str, required=False
)
set_children_parser.add_argument(
"--proportions", dest="proportions", type=str, required=False
)
set_children_parser.add_argument(
"--wait_for_inclusion",
dest="wait_for_inclusion",
action="store_true",
default=False,
help="""Wait for the transaction to be included in a block.""",
)
set_children_parser.add_argument(
"--wait_for_finalization",
dest="wait_for_finalization",
action="store_true",
default=True,
help="""Wait for the transaction to be finalized.""",
)
set_children_parser.add_argument(
"--prompt",
dest="prompt",
action="store_true",
default=False,
help="""Prompt for confirmation before proceeding.""",
)
bittensor.wallet.add_args(set_children_parser)
bittensor.subtensor.add_args(set_children_parser)


class GetChildrenCommand:
"""
Executes the ``get_children_info`` command to get all child hotkeys on a specified subnet on the Bittensor network.

This command is used to view delegated authority to different hotkeys on the subnet.

Usage:
Users can specify the subnet and see the children and the proportion that is given to them.

The command compiles a table showing:

- ChildHotkey: The hotkey associated with the child.
- ParentHotKey: The hotkey associated with the parent.
- Proportion: The proportion that is assigned to them.
- Expiration: The expiration of the hotkey.

Example usage::

btcli stake get_children --netuid 1

Note:
This command is for users who wish to see child hotkeys among different neurons (hotkeys) on the network.
"""

@staticmethod
def run(cli: "bittensor.cli"):
"""Get children hotkeys."""
try:
subtensor: "bittensor.subtensor" = bittensor.subtensor(
config=cli.config, log_verbose=False
)
return GetChildrenCommand._run(cli, subtensor)
finally:
if "subtensor" in locals():
subtensor.close()
bittensor.logging.debug("closing subtensor connection")

@staticmethod
def _run(cli: "bittensor.cli", subtensor: "bittensor.subtensor"):
# Get values if not set.
if not cli.config.is_set("netuid"):
cli.config.netuid = int(Prompt.ask("Enter netuid"))

# Get values if not set.
if not cli.config.is_set("hotkey"):
cli.config.netuid = Prompt.ask("Enter hotkey")

# Parse from strings
netuid = cli.config.netuid
hotkey = cli.config.hotkey

children = subtensor.get_children(hotkey, netuid)

GetChildrenCommand.render_table(subtensor, hotkey, children, netuid)

return children

@staticmethod
def check_config(config: "bittensor.config"):
if not config.is_set("wallet.name") and not config.no_prompt:
wallet_name = Prompt.ask("Enter wallet name", default=defaults.wallet.name)
config.wallet.name = str(wallet_name)
if not config.is_set("wallet.hotkey") and not config.no_prompt:
hotkey = Prompt.ask("Enter hotkey name", default=defaults.wallet.hotkey)
config.wallet.hotkey = str(hotkey)

@staticmethod
def add_args(parser: argparse.ArgumentParser):
parser = parser.add_parser(
"get_children", help="""Get child hotkeys on subnet."""
)
parser.add_argument("--netuid", dest="netuid", type=int, required=False)
parser.add_argument("--hotkey", dest="hotkey", type=str, required=False)

bittensor.wallet.add_args(parser)
bittensor.subtensor.add_args(parser)

@staticmethod
def render_table(
subtensor: "bittensor.subtensor",
hotkey: str,
children: list[Tuple[int, str]],
netuid: int,
):
console = Console()

# Initialize Rich table for pretty printing
table = Table(
show_header=True,
header_style="bold magenta",
border_style="green",
style="green",
)

# Add columns to the table with specific styles
table.add_column("Index", style="cyan", no_wrap=True, justify="right")
table.add_column("ChildHotkey", style="cyan", no_wrap=True)
table.add_column("Proportion", style="cyan", no_wrap=True, justify="right")
table.add_column("Total Stake", style="cyan", no_wrap=True, justify="right")

if not children:
console.print(table)

command = f"btcli stake set_children --children <child_hotkey> --hotkey <parent_hotkey> --netuid {netuid} --proportion <float>"
console.print(f"There are currently no child hotkeys on subnet {netuid}.")
console.print(
f"To add a child hotkey you can run the command: [white]{command}[/white]"
)
return

console.print("ParentHotKey:", style="cyan", no_wrap=True)
console.print(hotkey)

# calculate totals
total_proportion = 0
total_stake = 0

children_info = []
for child in children:
proportion = child[0]
child_hotkey = child[1]
child_stake = subtensor.get_total_stake_for_hotkey(
ss58_address=child_hotkey
) or Balance(0)

# add to totals
total_proportion += proportion
total_stake += child_stake

children_info.append((proportion, child_hotkey, child_stake))

children_info.sort(
key=lambda x: x[0], reverse=True
) # sorting by proportion (highest first)

# add the children info to the table
for i, (proportion, hotkey, stake) in enumerate(children_info, 1):
table.add_row(
str(i),
hotkey,
str(proportion),
str(stake),
)

# add totals row
table.add_row("", "Total", str(total_proportion), str(total_stake), "")
console.print(table)
Loading
Loading