From 50572ee3f0b87c40ec33891ad3b3e4b0d730ba31 Mon Sep 17 00:00:00 2001 From: Benjamin Himes Date: Wed, 29 Jan 2025 16:55:43 +0200 Subject: [PATCH 1/2] Allow display of basic information about encrypted hotkeys in wallets in `btcli w list` --- bittensor_cli/cli.py | 2 +- bittensor_cli/src/bittensor/utils.py | 40 +++++++++++++++++++----- bittensor_cli/src/commands/wallets.py | 12 +++---- tests/e2e_tests/test_wallet_creations.py | 4 +-- 4 files changed, 40 insertions(+), 18 deletions(-) diff --git a/bittensor_cli/cli.py b/bittensor_cli/cli.py index 5f3dfa59..b020e1ba 100755 --- a/bittensor_cli/cli.py +++ b/bittensor_cli/cli.py @@ -1252,7 +1252,7 @@ def wallet_list( """ Displays all the wallets and their corresponding hotkeys that are located in the wallet path specified in the config. - The output display shows each wallet and its associated `ss58` addresses for the coldkey public key and any hotkeys. The output is presented in a hierarchical tree format, with each wallet as a root node and any associated hotkeys as child nodes. The `ss58` address is displayed for each coldkey and hotkey that is not encrypted and exists on the device. + The output display shows each wallet and its associated `ss58` addresses for the coldkey public key and any hotkeys. The output display shows each wallet and its associated `ss58` addresses for the coldkey public key and any hotkeys. The output is presented in a hierarchical tree format, with each wallet as a root node and any associated hotkeys as child nodes. The `ss58` address (or an `` marker, for encrypted hotkeys) is displayed for each coldkey and hotkey that exists on the device. Upon invocation, the command scans the wallet directory and prints a list of all the wallets, indicating whether the public keys are available (`?` denotes unavailable or encrypted keys). diff --git a/bittensor_cli/src/bittensor/utils.py b/bittensor_cli/src/bittensor/utils.py index 71d5e12a..2463c618 100644 --- a/bittensor_cli/src/bittensor/utils.py +++ b/bittensor_cli/src/bittensor/utils.py @@ -28,9 +28,7 @@ if TYPE_CHECKING: from bittensor_cli.src.bittensor.chain_data import SubnetHyperparameters - from bittensor_cli.src.bittensor.async_substrate_interface import ( - AsyncSubstrateInterface, - ) + console = Console() err_console = Console(stderr=True) @@ -39,6 +37,23 @@ UnlockStatus = namedtuple("UnlockStatus", ["success", "message"]) +class _Hotkey: + def __init__(self, hotkey_ss58=None): + self.ss58_address = hotkey_ss58 + + +class WalletLike: + def __init__(self, name=None, hotkey_ss58=None, hotkey_str=None): + self.name = name + self.hotkey_ss58 = hotkey_ss58 + self.hotkey_str = hotkey_str + self._hotkey = _Hotkey(hotkey_ss58) + + @property + def hotkey(self): + return self._hotkey + + def print_console(message: str, colour: str, title: str, console: Console): console.print( f"[bold {colour}][{title}]:[/bold {colour}] [{colour}]{message}[/{colour}]\n" @@ -197,13 +212,14 @@ def convert_root_weight_uids_and_vals_to_tensor( def get_hotkey_wallets_for_wallet( - wallet: Wallet, show_nulls: bool = False + wallet: Wallet, show_nulls: bool = False, show_encrypted: bool = False ) -> list[Optional[Wallet]]: """ Returns wallet objects with hotkeys for a single given wallet :param wallet: Wallet object to use for the path :param show_nulls: will add `None` into the output if a hotkey is encrypted or not on the device + :param show_encrypted: will add some basic info about the encrypted hotkey :return: a list of wallets (with Nones included for cases of a hotkey being encrypted or not on the device, if `show_nulls` is set to `True`) @@ -219,12 +235,18 @@ def get_hotkey_wallets_for_wallet( hotkey_for_name = Wallet(path=str(wallet_path), name=wallet.name, hotkey=h_name) try: if ( - hotkey_for_name.hotkey_file.exists_on_device() + exists := hotkey_for_name.hotkey_file.exists_on_device() and not hotkey_for_name.hotkey_file.is_encrypted() # and hotkey_for_name.coldkeypub.ss58_address and hotkey_for_name.hotkey.ss58_address ): hotkey_wallets.append(hotkey_for_name) + elif ( + show_encrypted and exists and hotkey_for_name.hotkey_file.is_encrypted() + ): + hotkey_wallets.append( + WalletLike(str(wallet_path), "", h_name) + ) elif show_nulls: hotkey_wallets.append(None) except ( @@ -507,7 +529,10 @@ def format_error_message(error_message: Union[dict, Exception]) -> str: # subtensor custom error marker if err_data.startswith("Custom error:"): - err_description = f"{err_data} | Please consult https://docs.bittensor.com/subtensor-nodes/subtensor-error-messages" + err_description = ( + f"{err_data} | Please consult " + f"https://docs.bittensor.com/subtensor-nodes/subtensor-error-messages" + ) else: err_description = err_data @@ -542,7 +567,8 @@ def decode_hex_identity_dict(info_dictionary) -> dict[str, Any]: """ Decodes hex-encoded strings in a dictionary. - This function traverses the given dictionary, identifies hex-encoded strings, and decodes them into readable strings. It handles nested dictionaries and lists within the dictionary. + This function traverses the given dictionary, identifies hex-encoded strings, and decodes them into readable + strings. It handles nested dictionaries and lists within the dictionary. Args: info_dictionary (dict): The dictionary containing hex-encoded strings to decode. diff --git a/bittensor_cli/src/commands/wallets.py b/bittensor_cli/src/commands/wallets.py index d49c03e2..9b55b4e5 100644 --- a/bittensor_cli/src/commands/wallets.py +++ b/bittensor_cli/src/commands/wallets.py @@ -52,16 +52,10 @@ retry_prompt, unlock_key, hex_to_bytes, + WalletLike, ) -class WalletLike: - def __init__(self, name=None, hotkey_ss58=None, hotkey_str=None): - self.name = name - self.hotkey_ss58 = hotkey_ss58 - self.hotkey_str = hotkey_str - - async def regen_coldkey( wallet: Wallet, mnemonic: Optional[str], @@ -497,7 +491,9 @@ async def wallet_list(wallet_path: str): wallet_tree = root.add( f"[bold blue]Coldkey[/bold blue] [green]{wallet.name}[/green] ss58_address [green]{coldkeypub_str}[/green]" ) - hotkeys = utils.get_hotkey_wallets_for_wallet(wallet, show_nulls=True) + hotkeys = utils.get_hotkey_wallets_for_wallet( + wallet, show_nulls=True, show_encrypted=True + ) for hkey in hotkeys: data = f"[bold red]Hotkey[/bold red][green] {hkey}[/green] (?)" if hkey: diff --git a/tests/e2e_tests/test_wallet_creations.py b/tests/e2e_tests/test_wallet_creations.py index 7490a480..52aa3139 100644 --- a/tests/e2e_tests/test_wallet_creations.py +++ b/tests/e2e_tests/test_wallet_creations.py @@ -373,7 +373,7 @@ def test_wallet_regen(wallet_setup, capfd): "--mnemonic", mnemonics["coldkey"], "--no-use-password", - "--overwrite" + "--overwrite", ], ) @@ -413,7 +413,7 @@ def test_wallet_regen(wallet_setup, capfd): wallet_path, "--ss58-address", ss58_address, - "--overwrite" + "--overwrite", ], ) From d2595f6ba9959ebac0fd0ca365f022ddd116a0b3 Mon Sep 17 00:00:00 2001 From: Benjamin Himes Date: Wed, 29 Jan 2025 17:12:00 +0200 Subject: [PATCH 2/2] Walrus operator --- bittensor_cli/src/bittensor/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bittensor_cli/src/bittensor/utils.py b/bittensor_cli/src/bittensor/utils.py index 2463c618..82f22972 100644 --- a/bittensor_cli/src/bittensor/utils.py +++ b/bittensor_cli/src/bittensor/utils.py @@ -235,7 +235,7 @@ def get_hotkey_wallets_for_wallet( hotkey_for_name = Wallet(path=str(wallet_path), name=wallet.name, hotkey=h_name) try: if ( - exists := hotkey_for_name.hotkey_file.exists_on_device() + (exists := hotkey_for_name.hotkey_file.exists_on_device()) and not hotkey_for_name.hotkey_file.is_encrypted() # and hotkey_for_name.coldkeypub.ss58_address and hotkey_for_name.hotkey.ss58_address