import argparse
import re
from typing import List, Optional, Dict
import numpy as np
import torch
from rich.prompt import Prompt
from rich.table import Table
import cybertensor
from cybertensor import __console__ as console
from cybertensor.commands import defaults
from cybertensor.commands.utils import DelegatesDetails, check_netuid_set
from cybertensor.config import Config
from cybertensor.wallet import Wallet
class RegisterSubnetworkCommand:
@staticmethod
def run(cli: "cybertensor.cli") -> None:
try:
cwtensor = cybertensor.cwtensor(config=cli.config, log_verbose=False)
RegisterSubnetworkCommand._run(cli, cwtensor)
finally:
if "cwtensor" in locals():
cwtensor.close()
cybertensor.logging.debug("closing cwtensor connection")
@staticmethod
def _run(cli: "cybertensor.cli", cwtensor: "cybertensor.cwtensor"):
config = cli.config.copy()
wallet = Wallet(config=cli.config)
cwtensor = cybertensor.cwtensor(config=config)
success = cwtensor.register_subnetwork(
wallet=wallet,
prompt=not cli.config.no_prompt,
)
@classmethod
def check_config(cls, config: "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)
@classmethod
def add_args(cls, parser: argparse.ArgumentParser):
parser = parser.add_parser(
"create",
help="""Create a new cybertensor subnetwork on this chain.""",
)
Wallet.add_args(parser)
cybertensor.cwtensor.add_args(parser)
class SubnetLockCostCommand:
@staticmethod
def run(cli: "cybertensor.cli") -> None:
try:
cwtensor = cybertensor.cwtensor(config=cli.config, log_verbose=False)
SubnetLockCostCommand._run(cli, cwtensor)
finally:
if "cwtensor" in locals():
cwtensor.close()
cybertensor.logging.debug("closing cwtensor connection")
@staticmethod
def _run(cli: "cybertensor.cli", cwtensor: "cybertensor.cwtensor"):
config = cli.config.copy()
try:
console.print(
f"Subnet lock cost: [green]{cybertensor.Balance( cwtensor.get_subnet_burn_cost() )}[/green]"
)
except Exception as e:
console.print(
f"Subnet lock cost: [red]Failed to get subnet lock cost[/red]"
f"Error: {e}"
)
@classmethod
def check_config(cls, config: "Config"):
pass
@classmethod
def add_args(cls, parser: argparse.ArgumentParser):
parser = parser.add_parser(
"lock_cost",
help=""" Return the lock cost to register a subnet""",
)
cybertensor.cwtensor.add_args(parser)
class SubnetListCommand:
@staticmethod
def run(cli: "cybertensor.cli") -> None:
try:
cwtensor = cybertensor.cwtensor(config=cli.config, log_verbose=False)
SubnetListCommand._run(cli, cwtensor)
finally:
if "cwtensor" in locals():
cwtensor.close()
cybertensor.logging.debug("closing cwtensor connection")
@staticmethod
def _run(cli: "cybertensor.cli", cwtensor: "cybertensor.cwtensor"):
subnets: List[cybertensor.SubnetInfo] = cwtensor.get_all_subnets_info()
rows = []
total_neurons = 0
delegate_info: Optional[Dict[str, DelegatesDetails]] = cwtensor.get_delegates()
for subnet in subnets:
total_neurons += subnet.max_n
rows.append(
(
str(subnet.netuid),
str(subnet.subnetwork_n),
str(cybertensor.utils.formatting.millify(subnet.max_n)),
f"{subnet.emission_value / cybertensor.utils.GIGA * 100:0.2f}%",
str(subnet.tempo),
f"{subnet.burn!s:8.8}",
str(cybertensor.utils.formatting.millify(subnet.difficulty)),
f"{delegate_info[subnet.owner].owner if subnet.owner in delegate_info else subnet.owner}",
f"{subnet.metadata}",
)
)
table = Table(
show_footer=True,
width=cli.config.get("width", None),
pad_edge=True,
box=None,
show_edge=True,
)
table.title = "[white]Subnets - {}".format(cwtensor.network)
table.add_column(
"[overline white]NETUID",
str(len(subnets)),
footer_style="overline white",
style="bold green",
justify="center",
)
table.add_column(
"[overline white]N",
str(total_neurons),
footer_style="overline white",
style="green",
justify="center",
)
table.add_column("[overline white]MAX_N", style="white", justify="center")
table.add_column("[overline white]EMISSION", style="white", justify="center")
table.add_column("[overline white]TEMPO", style="white", justify="center")
table.add_column("[overline white]RECYCLE", style="white", justify="center")
table.add_column("[overline white]POW", style="white", justify="center")
table.add_column("[overline white]SUDO", style="white")
table.add_column("[overline white]METADATA", style="white")
for row in rows:
table.add_row(*row)
console.print(table)
@staticmethod
def check_config(config: "Config"):
pass
@staticmethod
def add_args(parser: argparse.ArgumentParser):
list_subnets_parser = parser.add_parser(
"list", help="""List all subnets on the network"""
)
cybertensor.cwtensor.add_args(list_subnets_parser)
HYPERPARAMS = {
"serving_rate_limit": "sudo_set_serving_rate_limit",
"min_difficulty": "sudo_set_min_difficulty",
"max_difficulty": "sudo_set_max_difficulty",
"weights_version_key": "sudo_set_weights_version_key",
"weights_rate_limit": "sudo_set_weights_set_rate_limit",
"weights_set_rate_limit": "sudo_set_weights_set_rate_limit",
"max_weight_limit": "sudo_set_max_weight_limit",
"immunity_period": "sudo_set_immunity_period",
"min_allowed_weights": "sudo_set_min_allowed_weights",
"activity_cutoff": "sudo_set_activity_cutoff",
"network_registration_allowed": "sudo_set_network_registration_allowed",
"network_pow_registration_allowed": "sudo_set_network_pow_registration_allowed",
"min_burn": "sudo_set_min_burn",
"max_burn": "sudo_set_max_burn",
"max_allowed_validators": "sudo_set_max_allowed_validators",
"metadata": "sudo_set_subnet_metadata",
}
class SubnetSudoCommand:
@staticmethod
def run(cli: "cybertensor.cli") -> None:
try:
cwtensor = cybertensor.cwtensor(config=cli.config, log_verbose=False)
SubnetSudoCommand._run(cli, cwtensor)
finally:
if "cwtensor" in locals():
cwtensor.close()
cybertensor.logging.debug("closing cwtensor connection")
@staticmethod
def _run(cli: "cybertensor.cli", cwtensor: "cybertensor.cwtensor"):
wallet = Wallet(config=cli.config)
print("\n")
SubnetHyperparamsCommand.run(cli)
if not cli.config.is_set("param") and not cli.config.no_prompt:
param = Prompt.ask("Enter hyperparameter", choices=HYPERPARAMS)
cli.config.param = str(param)
if not cli.config.is_set("value") and not cli.config.no_prompt:
value = Prompt.ask("Enter new value")
cli.config.value = value
if (
cli.config.param == "network_registration_allowed"
or cli.config.param == "network_pow_registration_allowed"
):
cli.config.value = True if cli.config.value.lower() == "true" else False
cwtensor.set_hyperparameter(
wallet,
netuid=cli.config.netuid,
parameter=cli.config.param,
value=cli.config.value,
prompt=not cli.config.no_prompt,
)
@staticmethod
def check_config(config: "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("netuid") and not config.no_prompt:
check_netuid_set(config, cybertensor.cwtensor(config=config, log_verbose=False))
@staticmethod
def add_args(parser: argparse.ArgumentParser):
parser = parser.add_parser("set", help="""Set hyperparameters for a subnet""")
parser.add_argument(
"--netuid", dest="netuid", type=int, required=False, default=False
)
parser.add_argument("--param", dest="param", type=str, required=False)
parser.add_argument("--value", dest="value", type=str, required=False)
Wallet.add_args(parser)
cybertensor.cwtensor.add_args(parser)
class SubnetHyperparamsCommand:
@staticmethod
def run(cli: "cybertensor.cli") -> None:
try:
cwtensor = cybertensor.cwtensor(config=cli.config, log_verbose=False)
SubnetHyperparamsCommand._run(cli, cwtensor)
finally:
if "cwtensor" in locals():
cwtensor.close()
cybertensor.logging.debug("closing cwtensor connection")
@staticmethod
def _run(cli: "cybertensor.cli", cwtensor: "cybertensor.cwtensor"):
subnet: cybertensor.SubnetHyperparameters = cwtensor.get_subnet_hyperparameters(
cli.config.netuid
)
table = Table(
show_footer=True,
width=cli.config.get("width", None),
pad_edge=True,
box=None,
show_edge=True,
)
table.title = "[white]Subnet Hyperparameters - NETUID: {} - {}".format(
cli.config.netuid, cwtensor.network
)
table.add_column("[overline white]HYPERPARAMETER", style="bold white")
table.add_column("[overline white]VALUE", style="green")
for param in subnet.__dict__:
table.add_row(" " + param, str(subnet.__dict__[param]))
console.print(table)
@staticmethod
def check_config(config: "Config"):
if not config.is_set("netuid") and not config.no_prompt:
check_netuid_set(config, cybertensor.cwtensor(config=config, log_verbose=False))
@staticmethod
def add_args(parser: argparse.ArgumentParser):
parser = parser.add_parser(
"hyperparameters", help="""View subnet hyperparameters"""
)
parser.add_argument(
"--netuid", dest="netuid", type=int, required=False, default=False
)
parser.add_argument(
"--no_prompt",
dest="no_prompt",
action="store_true",
help="""Set true to avoid prompting the user.""",
default=False,
)
cybertensor.cwtensor.add_args(parser)
class SubnetGetHyperparamsCommand:
@staticmethod
def run(cli: "cybertensor.cli") -> None:
try:
cwtensor = cybertensor.cwtensor(config=cli.config, log_verbose=False)
SubnetGetHyperparamsCommand._run(cli, cwtensor)
finally:
if "cwtensor" in locals():
cwtensor.close()
cybertensor.logging.debug("closing cwtensor connection")
@staticmethod
def _run(cli: "cybertensor.cli", cwtensor: "cybertensor.cwtensor"):
subnet: cybertensor.SubnetHyperparameters = cwtensor.get_subnet_hyperparameters(
cli.config.netuid
)
table = Table(
show_footer=True,
width=cli.config.get("width", None),
pad_edge=True,
box=None,
show_edge=True,
)
table.title = "[white]Subnet Hyperparameters - NETUID: {} - {}".format(
cli.config.netuid, cwtensor.network
)
table.add_column("[overline white]HYPERPARAMETER", style="white")
table.add_column("[overline white]VALUE", style="green")
for param in subnet.__dict__:
table.add_row(param, str(subnet.__dict__[param]))
console.print(table)
@staticmethod
def check_config(config: "Config"):
if not config.is_set("netuid") and not config.no_prompt:
check_netuid_set(config, cybertensor.cwtensor(config=config))
@staticmethod
def add_args(parser: argparse.ArgumentParser):
parser = parser.add_parser("get", help="""View subnet hyperparameters""")
parser.add_argument(
"--netuid", dest="netuid", type=int, required=False, default=False
)
parser.add_argument(
"--no_prompt",
dest="no_prompt",
action="store_true",
help="""Set true to avoid prompting the user.""",
default=False,
)
cybertensor.cwtensor.add_args(parser)
class SubnetSetWeightsCommand:
@staticmethod
def run(cli: "cybertensor.cli") -> None:
try:
cwtensor = cybertensor.cwtensor(config=cli.config, log_verbose=False)
SubnetSetWeightsCommand._run(cli, cwtensor)
finally:
if "cwtensor" in locals():
cwtensor.close()
cybertensor.logging.debug("closing cwtensor connection")
@staticmethod
def _run(cli: "cybertensor.cli", cwtensor: "cybertensor.cwtensor"):
wallet = Wallet(config=cli.config)
example_uids = range(3)
if not cli.config.is_set("uids"):
example = ", ".join(map(str, example_uids)) + " ..."
cli.config.uids = Prompt.ask(f"Enter uids (e.g. {example})")
if not cli.config.is_set("weights"):
example = (
", ".join(
map(str, ["{:.2f}".format(float(1 / len(example_uids))) for _ in example_uids])
)
+ " ..."
)
cli.config.weights = Prompt.ask(f"Enter weights (e.g. {example})")
uids = torch.tensor(
list(map(int, re.split(r"[ ,]+", cli.config.uids))), dtype=torch.long
)
weights = torch.tensor(
list(map(float, re.split(r"[ ,]+", cli.config.weights))),
dtype=torch.float32,
)
cwtensor.set_weights(
wallet=wallet,
netuid=cli.config.netuid,
uids=uids,
weights=weights,
version_key=0,
prompt=not cli.config.no_prompt,
wait_for_finalization=True,
)
@staticmethod
def add_args(parser: argparse.ArgumentParser):
parser = parser.add_parser("weights", help="""Set weights for subnet.""")
parser.add_argument("--uids", dest="uids", type=str, required=False)
parser.add_argument("--weights", dest="weights", type=str, required=False)
parser.add_argument(
"--netuid", dest="netuid", type=int, required=False, default=False
)
Wallet.add_args(parser)
cybertensor.cwtensor.add_args(parser)
@staticmethod
def check_config(config: "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)
if not config.is_set("netuid") and not config.no_prompt:
check_netuid_set(config, cybertensor.cwtensor(config=config))
class SubnetGetWeightsCommand:
@staticmethod
def run(cli: "cybertensor.cli") -> None:
try:
cwtensor = cybertensor.cwtensor(config=cli.config, log_verbose=False)
SubnetGetWeightsCommand._run(cli, cwtensor)
finally:
if "cwtensor" in locals():
cwtensor.close()
cybertensor.logging.debug("closing cwtensor connection")
@staticmethod
def _run(cli: "cybertensor.cli", cwtensor: "cybertensor.cwtensor"):
weights = cwtensor.weights(cli.config.netuid)
table = Table(show_footer=False)
table.title = "[white]Subnet Operators Weights"
table.add_column(
"[white]UIDS",
header_style="overline white",
footer_style="overline white",
style="rgb(50,163,219)",
no_wrap=True,
)
uid_to_weights = {}
netuids = set()
for matrix in weights:
[uid, weights_data] = matrix
if not len(weights_data):
uid_to_weights[uid] = {}
normalized_weights = []
else:
normalized_weights = np.array(weights_data)[:, 1] / max(
np.sum(weights_data, axis=0)[1], 1
)
for weight_data, normalized_weight in zip(weights_data, normalized_weights):
[netuid, _] = weight_data
netuids.add(netuid)
if uid not in uid_to_weights:
uid_to_weights[uid] = {}
uid_to_weights[uid][netuid] = normalized_weight
for netuid in netuids:
table.add_column(
f"[white]{netuid}",
header_style="overline white",
footer_style="overline white",
justify="right",
style="green",
no_wrap=True,
)
for uid in uid_to_weights:
row = [str(uid)]
uid_weights = uid_to_weights[uid]
for netuid in netuids:
if netuid in uid_weights:
normalized_weight = uid_weights[netuid]
row.append("{:0.2f}%".format(normalized_weight * 100))
else:
row.append("-")
table.add_row(*row)
table.show_footer = True
table.box = None
table.pad_edge = False
table.width = None
console.print(table)
@staticmethod
def add_args(parser: argparse.ArgumentParser):
parser = parser.add_parser(
"get_weights", help="""Get weights for subnet network."""
)
parser.add_argument(
"--netuid", dest="netuid", type=int, required=False, default=False
)
Wallet.add_args(parser)
cybertensor.cwtensor.add_args(parser)
@staticmethod
def check_config(config: "Config"):
if not config.is_set("netuid") and not config.no_prompt:
check_netuid_set(config, cybertensor.cwtensor(config=config))