Skip to content

Commit

Permalink
Set Child Hotkey
Browse files Browse the repository at this point in the history
  • Loading branch information
opendansor committed Jun 26, 2024
1 parent 03b7c25 commit 35a205b
Show file tree
Hide file tree
Showing 5 changed files with 181 additions and 232 deletions.
2 changes: 1 addition & 1 deletion bittensor/commands/stake.py
Original file line number Diff line number Diff line change
Expand Up @@ -653,7 +653,7 @@ def _run(cli: "bittensor.cli", subtensor: "bittensor.subtensor"):
)
else:
console.print(
":cross_mark:[red] Unable to set child hotkey.[/red]"
f":cross_mark:[red] Unable to set child hotkey.[/red] {message}"
)

@staticmethod
Expand Down
18 changes: 9 additions & 9 deletions bittensor/commands/weights.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,13 +70,13 @@ 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(f"Enter netuid"))
cli.config.netuid = int(Prompt.ask("Enter netuid"))

if not cli.config.is_set("uids"):
cli.config.uids = Prompt.ask(f"Enter UIDs (comma-separated)")
cli.config.uids = Prompt.ask("Enter UIDs (comma-separated)")

if not cli.config.is_set("weights"):
cli.config.weights = Prompt.ask(f"Enter weights (comma-separated)")
cli.config.weights = Prompt.ask("Enter weights (comma-separated)")

# Parse from string
netuid = cli.config.netuid
Expand Down Expand Up @@ -120,7 +120,7 @@ def _run(cli: "bittensor.cli", subtensor: "bittensor.subtensor"):

# Result
if success:
bittensor.__console__.print(f"Weights committed successfully")
bittensor.__console__.print("Weights committed successfully")
else:
bittensor.__console__.print(f"Failed to commit weights: {message}")

Expand Down Expand Up @@ -201,16 +201,16 @@ 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(f"Enter netuid"))
cli.config.netuid = int(Prompt.ask("Enter netuid"))

if not cli.config.is_set("uids"):
cli.config.uids = Prompt.ask(f"Enter UIDs (comma-separated)")
cli.config.uids = Prompt.ask("Enter UIDs (comma-separated)")

if not cli.config.is_set("weights"):
cli.config.weights = Prompt.ask(f"Enter weights (comma-separated)")
cli.config.weights = Prompt.ask("Enter weights (comma-separated)")

if not cli.config.is_set("salt"):
cli.config.salt = Prompt.ask(f"Enter salt (comma-separated)")
cli.config.salt = Prompt.ask("Enter salt (comma-separated)")

# Parse from string
netuid = cli.config.netuid
Expand Down Expand Up @@ -245,7 +245,7 @@ def _run(cli: "bittensor.cli", subtensor: "bittensor.subtensor"):
)

if success:
bittensor.__console__.print(f"Weights revealed successfully")
bittensor.__console__.print("Weights revealed successfully")
else:
bittensor.__console__.print(f"Failed to reveal weights: {message}")

Expand Down
106 changes: 76 additions & 30 deletions bittensor/extrinsics/staking.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
from rich.prompt import Confirm
from time import sleep
from typing import List, Union, Optional, Tuple

from bittensor.utils import weight_utils
from bittensor.utils.balance import Balance


Expand Down Expand Up @@ -525,24 +527,31 @@ def __do_add_stake_single(
return success


def __do_set_child_singular(
def do_set_child_singular_extrinsic(
subtensor: "bittensor.subtensor",
wallet: "bittensor.wallet",
hotkey_ss58: str,
amount: "bittensor.Balance",
hotkey: str,
child: str,
netuid: int,
proportion: float,
wait_for_inclusion: bool = True,
wait_for_finalization: bool = False,
prompt: bool = False,
) -> bool:
r"""
Executes a stake call to the chain using the wallet and the amount specified.
Sets child hotkey with a proportion assigned from the parent.
Args:
wallet (bittensor.wallet):
Bittensor wallet object.
hotkey_ss58 (str):
Hotkey to stake to.
amount (bittensor.Balance):
Amount to stake as Bittensor balance object.
hotkey (str):
Parent hotkey.
child (str):
Child hotkey.
netuid (int):
Unique identifier of for the subnet.
proportion (float):
Proportion assigned to child hotkey.
wait_for_inclusion (bool):
If set, waits for the extrinsic to enter a block before returning ``true``, or returns ``false`` if the extrinsic fails to enter the block within the timeout.
wait_for_finalization (bool):
Expand All @@ -551,35 +560,72 @@ def __do_set_child_singular(
If ``true``, the call waits for confirmation from the user before proceeding.
Returns:
success (bool):
Flag is ``true`` if extrinsic was finalized or uncluded in the block. If we did not wait for finalization / inclusion, the response is ``true``.
Flag is ``true`` if extrinsic was finalized or included in the block. If we did not wait for finalization / inclusion, the response is ``true``.
Raises:
bittensor.errors.StakeError:
bittensor.errors.ChildHotkeyError:
If the extrinsic fails to be finalized or included in the block.
bittensor.errors.NotDelegateError:
If the hotkey is not a delegate.
bittensor.errors.NotRegisteredError:
If the hotkey is not registered in any subnets.
"""
# Decrypt keys,
wallet.coldkey
# Ask before moving on.
if prompt:
if not Confirm.ask(
"Do you want to add child hotkey:\n[bold white] child: {}\n proportion: {}[/bold white ]?".format(
child, proportion
)
):
return False

hotkey_owner = subtensor.get_hotkey_owner(hotkey_ss58)
own_hotkey = wallet.coldkeypub.ss58_address == hotkey_owner
if not own_hotkey:
# We are delegating.
# Verify that the hotkey is a delegate.
if not subtensor.is_hotkey_delegate(hotkey_ss58=hotkey_ss58):
raise bittensor.errors.NotDelegateError(
"Hotkey: {} is not a delegate.".format(hotkey_ss58)
with bittensor.__console__.status(
":satellite: Setting child hotkey on [white]{}[/white] ...".format(
subtensor.network
)
):
try:
uid_val, proportion_val = weight_utils.convert_weights_and_uids_for_emit(
netuid, proportion
)

success = subtensor._do_stake(
wallet=wallet,
hotkey_ss58=hotkey_ss58,
amount=amount,
wait_for_inclusion=wait_for_inclusion,
wait_for_finalization=wait_for_finalization,
)
success, error_message = subtensor._do_set_child_singular(
wallet=wallet,
hotkey=hotkey,
child=child,
netuid=uid_val[0],
proportion=proportion_val[0],
wait_for_inclusion=wait_for_inclusion,
wait_for_finalization=wait_for_finalization,
)

return success
bittensor.__console__.print(success, error_message)

if not wait_for_finalization and not wait_for_inclusion:
return True

if success is True:
bittensor.__console__.print(
":white_heavy_check_mark: [green]Finalized[/green]"
)
bittensor.logging.success(
prefix="Set child hotkey",
suffix="<green>Finalized: </green>" + str(success),
)
return True
else:
bittensor.__console__.print(
f":cross_mark: [red]Failed[/red]: {error_message}"
)
bittensor.logging.warning(
prefix="Set child hotkey",
suffix="<red>Failed: </red>" + str(error_message),
)
return False

except Exception as e:
bittensor.__console__.print(
":cross_mark: [red]Failed[/red]: error:{}".format(e)
)
bittensor.logging.warning(
prefix="Set child hotkey", suffix="<red>Failed: </red>" + str(e)
)
return False
83 changes: 79 additions & 4 deletions bittensor/subtensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,11 @@
get_metadata,
)
from .extrinsics.set_weights import set_weights_extrinsic
from .extrinsics.staking import add_stake_extrinsic, add_stake_multiple_extrinsic
from .extrinsics.staking import (
add_stake_extrinsic,
add_stake_multiple_extrinsic,
do_set_child_singular_extrinsic,
)
from .extrinsics.transfer import transfer_extrinsic
from .extrinsics.unstaking import unstake_extrinsic, unstake_multiple_extrinsic
from .types import AxonServeCallParams, PrometheusServeCallParams
Expand Down Expand Up @@ -2179,6 +2183,7 @@ def set_child_singular(
proportion: float,
wait_for_inclusion: bool = True,
wait_for_finalization: bool = False,
prompt: bool = False,
) -> bool:
"""Sets a child hotkey extrinsic on the subnet.
Expand All @@ -2187,17 +2192,87 @@ def set_child_singular(
hotkey: (str): Hotkey ``ss58`` address of the parent.
child: (str): Hotkey ``ss58`` address of the child.
netuid (int): Unique identifier for the network.
proportion (int): Proportion allocated to the child.
proportion (float): Proportion allocated to the child.
wait_for_inclusion (bool): If ``true``, waits for inclusion before returning.
wait_for_finalization (bool): If ``true``, waits for finalization before returning.
prompt (bool, optional): If ``True``, prompts for user confirmation before proceeding.
Returns:
success (bool): ``True`` if the extrinsic was successful.
Raises:
ChildHotkeyError: If the extrinsic failed.
"""
pass

# Implementation here
return do_set_child_singular_extrinsic(
self,
wallet=wallet,
hotkey=hotkey,
child=child,
netuid=netuid,
proportion=proportion,
wait_for_inclusion=wait_for_inclusion,
wait_for_finalization=wait_for_finalization,
prompt=prompt,
)

def _do_set_child_singular(
self,
wallet: "bittensor.wallet",
hotkey: str,
child: str,
netuid: int,
proportion: int,
wait_for_inclusion: bool = True,
wait_for_finalization: bool = False,
):
"""Sends a child hotkey extrinsic on the chain.
Args:
wallet (:func:`bittensor.wallet`): Wallet object that can sign the extrinsic.
hotkey: (str): Hotkey ``ss58`` address of the parent.
child: (str): Hotkey ``ss58`` address of the child.
netuid (int): Unique identifier for the network in u64 format.
proportion (int): Proportion allocated to the child in u64 format.
wait_for_inclusion (bool): If ``true``, waits for inclusion before returning.
wait_for_finalization (bool): If ``true``, waits for finalization before returning.
Returns:
success (bool): ``True`` if the extrinsic was successful.
"""

@retry(delay=1, tries=3, backoff=2, max_delay=4, logger=_logger)
def make_substrate_call_with_retry():
# create extrinsic call
call = self.substrate.compose_call(
call_module="SubtensorModule",
call_function="set_child_singular",
call_params={
"hotkey": hotkey,
"child": child,
"netuid": netuid,
"proportion": proportion,
},
)
extrinsic = self.substrate.create_signed_extrinsic(
call=call, keypair=wallet.coldkey
)
response = self.substrate.submit_extrinsic(
extrinsic,
wait_for_inclusion=wait_for_inclusion,
wait_for_finalization=wait_for_finalization,
)

# We only wait here if we expect finalization.
if not wait_for_finalization and not wait_for_inclusion:
return True

# process if registration successful, try again if pow is still valid
response.process_events()
if not response.is_success:
return False, format_error_message(response.error_message)
# Successful registration
else:
return True, None

return make_substrate_call_with_retry()

#############
# Unstaking #
Expand Down
Loading

0 comments on commit 35a205b

Please sign in to comment.