Source code for bittensor.commands.identity

import argparse
from rich.table import Table
from rich.prompt import Prompt
from sys import getsizeof

import bittensor


[docs] class SetIdentityCommand: """ Executes the :func:`set_identity` command within the Bittensor network, which allows for the creation or update of a delegate's on-chain identity. This identity includes various attributes such as display name, legal name, web URL, PGP fingerprint, and contact information, among others. Optional Arguments: - ``display``: The display name for the identity. - ``legal``: The legal name for the identity. - ``web``: The web URL for the identity. - ``riot``: The riot handle for the identity. - ``email``: The email address for the identity. - ``pgp_fingerprint``: The PGP fingerprint for the identity. - ``image``: The image URL for the identity. - ``info``: The info for the identity. - ``twitter``: The X (twitter) URL for the identity. The command prompts the user for the different identity attributes and validates the input size for each attribute. It provides an option to update an existing validator hotkey identity. If the user consents to the transaction cost, the identity is updated on the blockchain. Each field has a maximum size of 64 bytes. The PGP fingerprint field is an exception and has a maximum size of 20 bytes. The user is prompted to enter the PGP fingerprint as a hex string, which is then converted to bytes. The user is also prompted to enter the coldkey or hotkey ``ss58`` address for the identity to be updated. If the user does not have a hotkey, the coldkey address is used by default. If setting a validator identity, the hotkey will be used by default. If the user is setting an identity for a subnet, the coldkey will be used by default. Usage: The user should call this command from the command line and follow the interactive prompts to enter or update the identity information. The command will display the updated identity details in a table format upon successful execution. Example usage:: btcli wallet set_identity Note: This command should only be used if the user is willing to incur the 1 TAO transaction fee associated with setting an identity on the blockchain. It is a high-level command that makes changes to the blockchain state and should not be used programmatically as part of other scripts or applications. """
[docs] def run(cli: "bittensor.cli"): r"""Create a new or update existing identity on-chain.""" try: subtensor: "bittensor.subtensor" = bittensor.subtensor( config=cli.config, log_verbose=False ) SetIdentityCommand._run(cli, subtensor) finally: if "subtensor" in locals(): subtensor.close() bittensor.logging.debug("closing subtensor connection")
[docs] def _run(cli: "bittensor.cli", subtensor: "bittensor.subtensor"): r"""Create a new or update existing identity on-chain.""" console = bittensor.__console__ wallet = bittensor.wallet(config=cli.config) id_dict = { "display": cli.config.display, "legal": cli.config.legal, "web": cli.config.web, "pgp_fingerprint": cli.config.pgp_fingerprint, "riot": cli.config.riot, "email": cli.config.email, "image": cli.config.image, "twitter": cli.config.twitter, "info": cli.config.info, } for field, string in id_dict.items(): if getsizeof(string) > 113: # 64 + 49 overhead bytes for string raise ValueError(f"Identity value `{field}` must be <= 64 raw bytes") identified = ( wallet.hotkey.ss58_address if str( Prompt.ask( "Are you updating a validator hotkey identity?", default="y", choices=["y", "n"], ) ).lower() == "y" else None ) if ( str( Prompt.ask( "Cost to register an Identity is [bold white italic]0.1 Tao[/bold white italic], are you sure you wish to continue?", default="n", choices=["y", "n"], ) ).lower() == "n" ): console.print(":cross_mark: Aborted!") exit(0) 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 with console.status(":satellite: [bold green]Updating identity on-chain..."): try: subtensor.update_identity( identified=identified, wallet=wallet, params=id_dict, ) except Exception as e: console.print(f"[red]:cross_mark: Failed![/red] {e}") exit(1) console.print(":white_heavy_check_mark: Success!") identity = subtensor.query_identity(identified or wallet.coldkey.ss58_address) table = Table(title="[bold white italic]Updated On-Chain Identity") table.add_column("Key", justify="right", style="cyan", no_wrap=True) table.add_column("Value", style="magenta") table.add_row("Address", identified or wallet.coldkey.ss58_address) for key, value in identity.items(): table.add_row(key, str(value) if value is not None else "None") console.print(table)
[docs] @staticmethod def check_config(config: "bittensor.config"): if not config.is_set("wallet.name") and not config.no_prompt: config.wallet.name = Prompt.ask( "Enter wallet name", default=bittensor.defaults.wallet.name ) if not config.is_set("wallet.hotkey") and not config.no_prompt: config.wallet.hotkey = Prompt.ask( "Enter wallet hotkey", default=bittensor.defaults.wallet.hotkey ) if not config.is_set("subtensor.network") and not config.no_prompt: config.subtensor.network = Prompt.ask( "Enter subtensor network", default=bittensor.defaults.subtensor.network, choices=bittensor.__networks__, ) ( _, config.subtensor.chain_endpoint, ) = bittensor.subtensor.determine_chain_endpoint_and_network( config.subtensor.network ) if not config.is_set("display") and not config.no_prompt: config.display = Prompt.ask("Enter display name", default="") if not config.is_set("legal") and not config.no_prompt: config.legal = Prompt.ask("Enter legal string", default="") if not config.is_set("web") and not config.no_prompt: config.web = Prompt.ask("Enter web url", default="") if not config.is_set("pgp_fingerprint") and not config.no_prompt: config.pgp_fingerprint = Prompt.ask( "Enter pgp fingerprint (must be 20 bytes)", default=None ) if not config.is_set("riot") and not config.no_prompt: config.riot = Prompt.ask("Enter riot", default="") if not config.is_set("email") and not config.no_prompt: config.email = Prompt.ask("Enter email address", default="") if not config.is_set("image") and not config.no_prompt: config.image = Prompt.ask("Enter image url", default="") if not config.is_set("twitter") and not config.no_prompt: config.twitter = Prompt.ask("Enter twitter url", default="") if not config.is_set("info") and not config.no_prompt: config.info = Prompt.ask("Enter info", default="")
[docs] @staticmethod def add_args(parser: argparse.ArgumentParser): new_coldkey_parser = parser.add_parser( "set_identity", help="""Create or update identity on-chain for a given cold wallet. Must be a subnet owner.""", ) new_coldkey_parser.add_argument( "--display", type=str, help="""The display name for the identity.""", ) new_coldkey_parser.add_argument( "--legal", type=str, help="""The legal name for the identity.""", ) new_coldkey_parser.add_argument( "--web", type=str, help="""The web url for the identity.""", ) new_coldkey_parser.add_argument( "--riot", type=str, help="""The riot handle for the identity.""", ) new_coldkey_parser.add_argument( "--email", type=str, help="""The email address for the identity.""", ) new_coldkey_parser.add_argument( "--pgp_fingerprint", type=str, help="""The pgp fingerprint for the identity.""", ) new_coldkey_parser.add_argument( "--image", type=str, help="""The image url for the identity.""", ) new_coldkey_parser.add_argument( "--info", type=str, help="""The info for the identity.""", ) new_coldkey_parser.add_argument( "--twitter", type=str, help="""The twitter url for the identity.""", ) bittensor.wallet.add_args(new_coldkey_parser) bittensor.subtensor.add_args(new_coldkey_parser)
[docs] class GetIdentityCommand: """ Executes the :func:`get_identity` command, which retrieves and displays the identity details of a user's coldkey or hotkey associated with the Bittensor network. This function queries the subtensor chain for information such as the stake, rank, and trust associated with the provided key. Optional Arguments: - ``key``: The ``ss58`` address of the coldkey or hotkey to query. The command performs the following actions: - Connects to the subtensor network and retrieves the identity information. - Displays the information in a structured table format. The displayed table includes: - **Address**: The ``ss58`` address of the queried key. - **Item**: Various attributes of the identity such as stake, rank, and trust. - **Value**: The corresponding values of the attributes. Usage: The user must provide an ``ss58`` address as input to the command. If the address is not provided in the configuration, the user is prompted to enter one. Example usage:: btcli wallet get_identity --key <s58_address> Note: This function is designed for CLI use and should be executed in a terminal. It is primarily used for informational purposes and has no side effects on the network state. """
[docs] def run(cli: "bittensor.cli"): r"""Queries the subtensor chain for user identity.""" try: subtensor: "bittensor.subtensor" = bittensor.subtensor( config=cli.config, log_verbose=False ) GetIdentityCommand._run(cli, subtensor) finally: if "subtensor" in locals(): subtensor.close() bittensor.logging.debug("closing subtensor connection")
[docs] def _run(cli: "bittensor.cli", subtensor: "bittensor.subtensor"): console = bittensor.__console__ with console.status(":satellite: [bold green]Querying chain identity..."): identity = subtensor.query_identity(cli.config.key) table = Table(title="[bold white italic]On-Chain Identity") table.add_column("Item", justify="right", style="cyan", no_wrap=True) table.add_column("Value", style="magenta") table.add_row("Address", cli.config.key) for key, value in identity.items(): table.add_row(key, str(value) if value is not None else "None") console.print(table)
[docs] @staticmethod def check_config(config: "bittensor.config"): if not config.is_set("key") and not config.no_prompt: config.key = Prompt.ask( "Enter coldkey or hotkey ss58 address", default=None ) if config.key is None: raise ValueError("key must be set") if not config.is_set("subtensor.network") and not config.no_prompt: config.subtensor.network = Prompt.ask( "Enter subtensor network", default=bittensor.defaults.subtensor.network, choices=bittensor.__networks__, ) ( _, config.subtensor.chain_endpoint, ) = bittensor.subtensor.determine_chain_endpoint_and_network( config.subtensor.network )
[docs] @staticmethod def add_args(parser: argparse.ArgumentParser): new_coldkey_parser = parser.add_parser( "get_identity", help="""Creates a new coldkey (for containing balance) under the specified path. """, ) new_coldkey_parser.add_argument( "--key", type=str, default=None, help="""The coldkey or hotkey ss58 address to query.""", ) bittensor.wallet.add_args(new_coldkey_parser) bittensor.subtensor.add_args(new_coldkey_parser)