# The MIT License (MIT)
# Copyright © 2021 Yuma Rao
# Copyright © 2023 Opentensor Foundation
# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
# documentation files (the “Software”), to deal in the Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
# and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
# The above copyright notice and this permission notice shall be included in all copies or substantial portions of
# the Software.
# THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
# THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.
import bittensor
import time
import logging
import numpy as np
from numpy.typing import NDArray
from rich.prompt import Confirm
from typing import Union, List
import bittensor.utils.weight_utils as weight_utils
from bittensor.btlogging.defines import BITTENSOR_LOGGER_NAME
from bittensor.utils.registration import torch, legacy_torch_api_compat
logger = logging.getLogger(BITTENSOR_LOGGER_NAME)
[docs]
def root_register_extrinsic(
subtensor: "bittensor.subtensor",
wallet: "bittensor.wallet",
wait_for_inclusion: bool = False,
wait_for_finalization: bool = True,
prompt: bool = False,
) -> bool:
r"""Registers the wallet to root network.
Args:
wallet (bittensor.wallet):
Bittensor wallet object.
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):
If set, waits for the extrinsic to be finalized on the chain before returning ``true``, or returns ``false`` if the extrinsic fails to be finalized within the timeout.
prompt (bool):
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``.
"""
try:
wallet.coldkey # unlock coldkey
except bittensor.KeyFileError:
bittensor.__console__.print(
":cross_mark: [red]Keyfile is corrupt, non-writable, non-readable or the password used to decrypt is invalid[/red]:[bold white]\n [/bold white]"
)
return False
is_registered = subtensor.is_hotkey_registered(
netuid=0, hotkey_ss58=wallet.hotkey.ss58_address
)
if is_registered:
bittensor.__console__.print(
":white_heavy_check_mark: [green]Already registered on root network.[/green]"
)
return True
if prompt:
# Prompt user for confirmation.
if not Confirm.ask("Register to root network?"):
return False
with bittensor.__console__.status(":satellite: Registering to root network..."):
success, err_msg = subtensor._do_root_register(
wallet=wallet,
wait_for_inclusion=wait_for_inclusion,
wait_for_finalization=wait_for_finalization,
)
if not success:
bittensor.__console__.print(f":cross_mark: [red]Failed[/red]: {err_msg}")
time.sleep(0.5)
# Successful registration, final check for neuron and pubkey
else:
is_registered = subtensor.is_hotkey_registered(
netuid=0, hotkey_ss58=wallet.hotkey.ss58_address
)
if is_registered:
bittensor.__console__.print(
":white_heavy_check_mark: [green]Registered[/green]"
)
return True
else:
# neuron not found, try again
bittensor.__console__.print(
":cross_mark: [red]Unknown error. Neuron not found.[/red]"
)
[docs]
@legacy_torch_api_compat
def set_root_weights_extrinsic(
subtensor: "bittensor.subtensor",
wallet: "bittensor.wallet",
netuids: Union[NDArray[np.int64], "torch.LongTensor", List[int]],
weights: Union[NDArray[np.float32], "torch.FloatTensor", List[float]],
version_key: int = 0,
wait_for_inclusion: bool = False,
wait_for_finalization: bool = False,
prompt: bool = False,
) -> bool:
r"""Sets the given weights and values on chain for wallet hotkey account.
Args:
wallet (bittensor.wallet):
Bittensor wallet object.
netuids (Union[NDArray[np.int64], torch.LongTensor, List[int]]):
The ``netuid`` of the subnet to set weights for.
weights (Union[NDArray[np.float32], torch.FloatTensor, list]):
Weights to set. These must be ``float`` s and must correspond to the passed ``netuid`` s.
version_key (int):
The version key of the validator.
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):
If set, waits for the extrinsic to be finalized on the chain before returning ``true``, or returns ``false`` if the extrinsic fails to be finalized within the timeout.
prompt (bool):
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``.
"""
try:
wallet.coldkey # unlock coldkey
except bittensor.KeyFileError:
bittensor.__console__.print(
":cross_mark: [red]Keyfile is corrupt, non-writable, non-readable or the password used to decrypt is invalid[/red]:[bold white]\n [/bold white]"
)
return False
# First convert types.
if isinstance(netuids, list):
netuids = np.array(netuids, dtype=np.int64)
if isinstance(weights, list):
weights = np.array(weights, dtype=np.float32)
# Get weight restrictions.
min_allowed_weights = subtensor.min_allowed_weights(netuid=0)
max_weight_limit = subtensor.max_weight_limit(netuid=0)
# Get non zero values.
non_zero_weight_idx = np.argwhere(weights > 0).squeeze(axis=1)
non_zero_weight_uids = netuids[non_zero_weight_idx]
non_zero_weights = weights[non_zero_weight_idx]
if non_zero_weights.size < min_allowed_weights:
raise ValueError(
"The minimum number of weights required to set weights is {}, got {}".format(
min_allowed_weights, non_zero_weights.size
)
)
# Normalize the weights to max value.
formatted_weights = bittensor.utils.weight_utils.normalize_max_weight(
x=weights, limit=max_weight_limit
)
bittensor.__console__.print(
f"\nRaw Weights -> Normalized weights: \n\t{weights} -> \n\t{formatted_weights}\n"
)
# Ask before moving on.
if prompt:
if not Confirm.ask(
"Do you want to set the following root weights?:\n[bold white] weights: {}\n uids: {}[/bold white ]?".format(
formatted_weights, netuids
)
):
return False
with bittensor.__console__.status(
":satellite: Setting root weights on [white]{}[/white] ...".format(
subtensor.network
)
):
try:
weight_uids, weight_vals = weight_utils.convert_weights_and_uids_for_emit(
netuids, weights
)
success, error_message = subtensor._do_set_root_weights(
wallet=wallet,
netuid=0,
uids=weight_uids,
vals=weight_vals,
version_key=version_key,
wait_for_finalization=wait_for_finalization,
wait_for_inclusion=wait_for_inclusion,
)
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 weights",
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 weights",
suffix="<red>Failed: </red>" + str(error_message),
)
return False
except Exception as e:
# TODO( devs ): lets remove all of the bittensor.__console__ calls and replace with the bittensor logger.
bittensor.__console__.print(
":cross_mark: [red]Failed[/red]: error:{}".format(e)
)
bittensor.logging.warning(
prefix="Set weights", suffix="<red>Failed: </red>" + str(e)
)
return False