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

Adds subnet identities set/get #316

Merged
merged 2 commits into from
Feb 14, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
119 changes: 119 additions & 0 deletions bittensor_cli/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -804,6 +804,12 @@ def __init__(self):
self.subnets_app.command(
"price", rich_help_panel=HELP_PANELS["SUBNETS"]["INFO"]
)(self.subnets_price)
self.subnets_app.command(
"set-identity", rich_help_panel=HELP_PANELS["SUBNETS"]["IDENTITY"]
)(self.subnets_set_identity)
self.subnets_app.command(
"get-identity", rich_help_panel=HELP_PANELS["SUBNETS"]["IDENTITY"]
)(self.subnets_get_identity)

# weights commands
self.weights_app.command(
Expand Down Expand Up @@ -4452,6 +4458,7 @@ def subnets_create(
validate=WV.WALLET_AND_HOTKEY,
)
identity = prompt_for_subnet_identity(
current_identity={},
subnet_name=subnet_name,
github_repo=github_repo,
subnet_contact=subnet_contact,
Expand Down Expand Up @@ -4482,6 +4489,118 @@ def subnets_create(
verbose=verbose,
)

def subnets_get_identity(
self,
network: Optional[list[str]] = Options.network,
netuid: int = Options.netuid,
quiet: bool = Options.quiet,
verbose: bool = Options.verbose,
):
"""
Get the identity information for a subnet.

This command displays the identity information of a subnet including name, GitHub repo, contact details, etc.

[green]$[/green] btcli subnets get-identity --netuid 1
"""
self.verbosity_handler(quiet, verbose)
return self._run_command(
subnets.get_identity(
self.initialize_chain(network),
netuid,
)
)

def subnets_set_identity(
self,
wallet_name: str = Options.wallet_name,
wallet_path: str = Options.wallet_path,
wallet_hotkey: str = Options.wallet_hotkey,
network: Optional[list[str]] = Options.network,
netuid: int = Options.netuid,
subnet_name: Optional[str] = typer.Option(
None, "--subnet-name", "--name", help="Name of the subnet"
),
github_repo: Optional[str] = typer.Option(
None, "--github-repo", "--repo", help="GitHub repository URL"
),
subnet_contact: Optional[str] = typer.Option(
None,
"--subnet-contact",
"--contact",
"--email",
help="Contact email for subnet",
),
subnet_url: Optional[str] = typer.Option(
None, "--subnet-url", "--url", help="Subnet URL"
),
discord: Optional[str] = typer.Option(
None, "--discord-handle", "--discord", help="Discord handle"
),
description: Optional[str] = typer.Option(
None, "--description", help="Description"
),
additional_info: Optional[str] = typer.Option(
None, "--additional-info", help="Additional information"
),
prompt: bool = Options.prompt,
quiet: bool = Options.quiet,
verbose: bool = Options.verbose,
):
"""
Set or update the identity information for a subnet.

This command allows subnet owners to set or update identity information like name, GitHub repo, contact details, etc.

[bold]Common Examples:[/bold]

1. Interactive subnet identity setting:
[green]$[/green] btcli subnets set-identity --netuid 1

2. Set subnet identity with specific values:
[green]$[/green] btcli subnets set-identity --netuid 1 --subnet-name MySubnet --github-repo https://github.com/myorg/mysubnet --subnet-contact team@mysubnet.net
"""
self.verbosity_handler(quiet, verbose)
wallet = self.wallet_ask(
wallet_name,
wallet_path,
wallet_hotkey,
ask_for=[WO.NAME],
validate=WV.WALLET,
)

current_identity = self._run_command(
subnets.get_identity(
self.initialize_chain(network),
netuid,
f"Current Subnet {netuid}'s Identity",
),
exit_early=False,
)
if current_identity is None:
raise typer.Exit()

identity = prompt_for_subnet_identity(
current_identity=current_identity,
subnet_name=subnet_name,
github_repo=github_repo,
subnet_contact=subnet_contact,
subnet_url=subnet_url,
discord=discord,
description=description,
additional=additional_info,
)

return self._run_command(
subnets.set_identity(
wallet,
self.initialize_chain(network),
netuid,
identity,
prompt,
)
)

def subnets_pow_register(
self,
wallet_name: Optional[str] = Options.wallet_name,
Expand Down
1 change: 1 addition & 0 deletions bittensor_cli/src/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -710,6 +710,7 @@ class WalletValidationTypes(Enum):
"INFO": "Subnet Information",
"CREATION": "Subnet Creation & Management",
"REGISTER": "Neuron Registration",
"IDENTITY": "Subnet Identity Management",
},
"WEIGHTS": {"COMMIT_REVEAL": "Commit / Reveal"},
}
Expand Down
3 changes: 2 additions & 1 deletion bittensor_cli/src/bittensor/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -1126,6 +1126,7 @@ def prompt_for_identity(


def prompt_for_subnet_identity(
current_identity: dict,
subnet_name: Optional[str],
github_repo: Optional[str],
subnet_contact: Optional[str],
Expand Down Expand Up @@ -1210,7 +1211,7 @@ def prompt_for_subnet_identity(
prompt,
rejection=rejection_func,
rejection_text=rejection_msg,
default=None, # Maybe we can add some defaults later
default=current_identity.get(key, ""),
show_default=True,
)

Expand Down
144 changes: 144 additions & 0 deletions bittensor_cli/src/commands/subnets/subnets.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
update_metadata_table,
prompt_for_identity,
get_subnet_name,
unlock_key,
)

if TYPE_CHECKING:
Expand Down Expand Up @@ -2026,3 +2027,146 @@ async def metagraph_cmd(
table.add_row(*row)

console.print(table)


def create_identity_table(title: str = None):
if not title:
title = "Subnet Identity"

table = Table(
Column(
"Item",
justify="right",
style=COLOR_PALETTE["GENERAL"]["SUBHEADING_MAIN"],
no_wrap=True,
),
Column("Value", style=COLOR_PALETTE["GENERAL"]["SUBHEADING"]),
title=f"\n[{COLOR_PALETTE['GENERAL']['HEADER']}]{title}\n",
show_footer=True,
show_edge=False,
header_style="bold white",
border_style="bright_black",
style="bold",
title_justify="center",
show_lines=False,
pad_edge=True,
)
return table


async def set_identity(
wallet: "Wallet",
subtensor: "SubtensorInterface",
netuid: int,
subnet_identity: dict,
prompt: bool = False,
) -> bool:
"""Set identity information for a subnet"""

if not await subtensor.subnet_exists(netuid):
err_console.print(f"Subnet {netuid} does not exist")
return False

identity_data = {
"netuid": netuid,
"subnet_name": subnet_identity.get("subnet_name", ""),
"github_repo": subnet_identity.get("github_repo", ""),
"subnet_contact": subnet_identity.get("subnet_contact", ""),
"subnet_url": subnet_identity.get("subnet_url", ""),
"discord": subnet_identity.get("discord", ""),
"description": subnet_identity.get("description", ""),
"additional": subnet_identity.get("additional", ""),
}

if not unlock_key(wallet).success:
return False

if prompt:
if not Confirm.ask(
"Are you sure you want to set subnet's identity? This is subject to a fee."
):
return False

call = await subtensor.substrate.compose_call(
call_module="SubtensorModule",
call_function="set_subnet_identity",
call_params=identity_data,
)

with console.status(
" :satellite: [dark_sea_green3]Setting subnet identity on-chain...",
spinner="earth",
):
success, err_msg = await subtensor.sign_and_send_extrinsic(call, wallet)

if not success:
err_console.print(f"[red]:cross_mark: Failed![/red] {err_msg}")
return False

console.print(
":white_heavy_check_mark: [dark_sea_green3]Successfully set subnet identity\n"
)

subnet = await subtensor.subnet(netuid)
identity = subnet.subnet_identity if subnet else None

if identity:
table = create_identity_table(title=f"New Subnet {netuid} Identity")
table.add_row("Netuid", str(netuid))
for key in [
"subnet_name",
"github_repo",
"subnet_contact",
"subnet_url",
"discord",
"description",
"additional",
]:
value = getattr(identity, key, None)
table.add_row(key, str(value) if value else "~")
console.print(table)

return True


async def get_identity(subtensor: "SubtensorInterface", netuid: int, title: str = None):
"""Fetch and display existing subnet identity information."""
if not title:
title = "Subnet Identity"

if not await subtensor.subnet_exists(netuid):
print_error(
f"Subnet {netuid} does not exist."
)
raise typer.Exit()

with console.status(
":satellite: [bold green]Querying subnet identity...", spinner="earth"
):
subnet = await subtensor.subnet(netuid)
identity = subnet.subnet_identity if subnet else None

if not identity:
err_console.print(
f"Existing subnet identity not found"
f" for subnet [blue]{netuid}[/blue]"
f" on {subtensor}"
)
return {}

if identity:
table = create_identity_table(title=f"Current Subnet {netuid} Identity")
table.add_row("Netuid", str(netuid))
for key in [
"subnet_name",
"github_repo",
"subnet_contact",
"subnet_url",
"discord",
"description",
"additional",
]:
value = getattr(identity, key, None)
table.add_row(key, str(value) if value else "~")
console.print(table)
return identity
Loading