Skip to content

Commit

Permalink
Merge pull request #316 from opentensor/feat/subnet-identities
Browse files Browse the repository at this point in the history
Adds subnet identities set/get
  • Loading branch information
unconst authored Feb 14, 2025
2 parents 7878c5c + 926b80d commit 5b44155
Show file tree
Hide file tree
Showing 4 changed files with 266 additions and 1 deletion.
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

0 comments on commit 5b44155

Please sign in to comment.