Skip to content
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
95 changes: 83 additions & 12 deletions bittensor_cli/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
validate_uri,
prompt_for_subnet_identity,
validate_rate_tolerance,
get_hotkey_pub_ss58,
)
from bittensor_cli.src.commands import sudo, wallets, view
from bittensor_cli.src.commands import weights as weights_cmds
Expand Down Expand Up @@ -791,6 +792,9 @@ def __init__(self):
self.wallet_app.command(
"regen-hotkey", rich_help_panel=HELP_PANELS["WALLET"]["SECURITY"]
)(self.wallet_regen_hotkey)
self.wallet_app.command(
"regen-hotkeypub", rich_help_panel=HELP_PANELS["WALLET"]["SECURITY"]
)(self.wallet_regen_hotkey_pub)
self.wallet_app.command(
"new-hotkey", rich_help_panel=HELP_PANELS["WALLET"]["MANAGEMENT"]
)(self.wallet_new_hotkey)
Expand Down Expand Up @@ -973,6 +977,10 @@ def __init__(self):
"regen_hotkey",
hidden=True,
)(self.wallet_regen_hotkey)
self.wallet_app.command(
"regen_hotkeypub",
hidden=True,
)(self.wallet_regen_hotkey_pub)
self.wallet_app.command(
"new_hotkey",
hidden=True,
Expand Down Expand Up @@ -1143,7 +1151,8 @@ async def _run():
exit_early is True
): # temporarily to handle multiple run commands in one session
try:
await self.subtensor.substrate.close()
if self.subtensor:
await self.subtensor.substrate.close()
raise typer.Exit()
except Exception as e: # ensures we always exit cleanly
if not isinstance(e, (typer.Exit, RuntimeError)):
Expand Down Expand Up @@ -1726,7 +1735,7 @@ def wallet_ask(
if return_wallet_and_hotkey:
valid = utils.is_valid_wallet(wallet)
if valid[1]:
return wallet, wallet.hotkey.ss58_address
return wallet, get_hotkey_pub_ss58(wallet)
else:
if wallet_hotkey and is_valid_ss58_address(wallet_hotkey):
return wallet, wallet_hotkey
Expand Down Expand Up @@ -2285,7 +2294,7 @@ def wallet_regen_coldkey_pub(

EXAMPLE

[green]$[/green] btcli wallet regen_coldkeypub --ss58_address 5DkQ4...
[green]$[/green] btcli wallet regen-coldkeypub --ss58_address 5DkQ4...

[bold]Note[/bold]: This command is particularly useful for users who need to regenerate their coldkeypub, perhaps due to file corruption or loss. You will need either ss58 address or public hex key from your old coldkeypub.txt for the wallet. It is a recovery-focused utility that ensures continued access to your wallet functionalities.
"""
Expand All @@ -2300,7 +2309,7 @@ def wallet_regen_coldkey_pub(

if not wallet_name:
wallet_name = Prompt.ask(
f"Enter the name of the [{COLORS.G.CK}]new wallet (coldkey)",
f"Enter the name of the [{COLORS.G.CK}]wallet for the new coldkeypub",
default=defaults.wallet.name,
)
wallet = Wallet(wallet_name, wallet_hotkey, wallet_path)
Expand All @@ -2317,7 +2326,7 @@ def wallet_regen_coldkey_pub(
address=ss58_address if ss58_address else public_key_hex
):
rich.print("[red]Error: Invalid SS58 address or public key![/red]")
raise typer.Exit()
return
return self._run_command(
wallets.regen_coldkey_pub(
wallet, ss58_address, public_key_hex, overwrite, json_output
Expand Down Expand Up @@ -2383,6 +2392,68 @@ def wallet_regen_hotkey(
)
)

def wallet_regen_hotkey_pub(
self,
wallet_name: Optional[str] = Options.wallet_name,
wallet_path: Optional[str] = Options.wallet_path,
wallet_hotkey: Optional[str] = Options.wallet_hotkey,
public_key_hex: Optional[str] = Options.public_hex_key,
ss58_address: Optional[str] = Options.ss58_address,
overwrite: bool = Options.overwrite,
quiet: bool = Options.quiet,
verbose: bool = Options.verbose,
json_output: bool = Options.json_output,
):
"""
Regenerates the public part of a hotkey (hotkeypub.txt) for a wallet.

Use this command when you need to move machine for subnet mining. Use the public key or SS58 address from your hotkeypub.txt that you have on another machine to regenerate the hotkeypub.txt on this new machine.

USAGE

The command requires either a public key in hexadecimal format or an ``SS58`` address from the existing hotkeypub.txt from old machine to regenerate the coldkeypub on the new machine.

EXAMPLE

[green]$[/green] btcli wallet regen-hotkeypub --ss58_address 5DkQ4...

[bold]Note[/bold]: This command is particularly useful for users who need to regenerate their hotkeypub, perhaps due to file corruption or loss. You will need either ss58 address or public hex key from your old hotkeypub.txt for the wallet. It is a recovery-focused utility that ensures continued access to your wallet functionalities.
"""
self.verbosity_handler(quiet, verbose, json_output)

if not wallet_path:
wallet_path = Prompt.ask(
"Enter the path to the wallets directory",
default=self.config.get("wallet_path") or defaults.wallet.path,
)
wallet_path = os.path.expanduser(wallet_path)

if not wallet_name:
wallet_name = Prompt.ask(
f"Enter the name of the [{COLORS.G.CK}]wallet for the new hotkeypub",
default=defaults.wallet.name,
)
wallet = Wallet(wallet_name, wallet_hotkey, wallet_path)

if not ss58_address and not public_key_hex:
prompt_answer = typer.prompt(
"Enter the ss58_address or the public key in hex"
)
if prompt_answer.startswith("0x"):
public_key_hex = prompt_answer
else:
ss58_address = prompt_answer
if not utils.is_valid_bittensor_address_or_public_key(
address=ss58_address if ss58_address else public_key_hex
):
rich.print("[red]Error: Invalid SS58 address or public key![/red]")
return False
return self._run_command(
wallets.regen_hotkey_pub(
wallet, ss58_address, public_key_hex, overwrite, json_output
)
)

def wallet_new_hotkey(
self,
wallet_name: Optional[str] = Options.wallet_name,
Expand Down Expand Up @@ -2502,7 +2573,7 @@ def wallet_associate_hotkey(
ask_for=[WO.NAME, WO.PATH, WO.HOTKEY],
validate=WV.WALLET_AND_HOTKEY,
)
hotkey_ss58 = wallet.hotkey.ss58_address
hotkey_ss58 = get_hotkey_pub_ss58(wallet)
hotkey_display = (
f"hotkey [blue]{wallet_hotkey}[/blue] "
f"[{COLORS.GENERAL.HK}]({hotkey_ss58})[/{COLORS.GENERAL.HK}]"
Expand Down Expand Up @@ -3518,7 +3589,7 @@ def stake_add(
ask_for=[WO.NAME, WO.HOTKEY, WO.PATH],
validate=WV.WALLET_AND_HOTKEY,
)
include_hotkeys = wallet.hotkey.ss58_address
include_hotkeys = get_hotkey_pub_ss58(wallet)

elif all_hotkeys or include_hotkeys or exclude_hotkeys:
wallet = self.wallet_ask(
Expand Down Expand Up @@ -3982,7 +4053,7 @@ def stake_move(
ask_for=[WO.NAME, WO.PATH, WO.HOTKEY],
validate=WV.WALLET_AND_HOTKEY,
)
destination_hotkey = destination_wallet.hotkey.ss58_address
destination_hotkey = get_hotkey_pub_ss58(destination_wallet)
else:
if is_valid_ss58_address(destination_hotkey):
destination_hotkey = destination_hotkey
Expand Down Expand Up @@ -4021,7 +4092,7 @@ def stake_move(
ask_for=[WO.NAME, WO.PATH, WO.HOTKEY],
validate=WV.WALLET_AND_HOTKEY,
)
origin_hotkey = wallet.hotkey.ss58_address
origin_hotkey = get_hotkey_pub_ss58(wallet)
else:
if is_valid_ss58_address(wallet_hotkey):
origin_hotkey = wallet_hotkey
Expand All @@ -4033,7 +4104,7 @@ def stake_move(
ask_for=[],
validate=WV.WALLET_AND_HOTKEY,
)
origin_hotkey = wallet.hotkey.ss58_address
origin_hotkey = get_hotkey_pub_ss58(wallet)

if not interactive_selection:
if origin_netuid is None:
Expand Down Expand Up @@ -4186,7 +4257,7 @@ def stake_transfer(
ask_for=[WO.NAME, WO.PATH, WO.HOTKEY],
validate=WV.WALLET_AND_HOTKEY,
)
origin_hotkey = wallet.hotkey.ss58_address
origin_hotkey = get_hotkey_pub_ss58(wallet)
else:
if is_valid_ss58_address(wallet_hotkey):
origin_hotkey = wallet_hotkey
Expand All @@ -4198,7 +4269,7 @@ def stake_transfer(
ask_for=[],
validate=WV.WALLET_AND_HOTKEY,
)
origin_hotkey = wallet.hotkey.ss58_address
origin_hotkey = get_hotkey_pub_ss58(wallet)

if not interactive_selection:
if origin_netuid is None:
Expand Down
54 changes: 29 additions & 25 deletions bittensor_cli/src/bittensor/extrinsics/registration.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
print_error,
unlock_key,
hex_to_bytes,
get_hotkey_pub_ss58,
)

if typing.TYPE_CHECKING:
Expand Down Expand Up @@ -490,7 +491,7 @@ async def register_extrinsic(

async def get_neuron_for_pubkey_and_subnet():
uid = await subtensor.query(
"SubtensorModule", "Uids", [netuid, wallet.hotkey.ss58_address]
"SubtensorModule", "Uids", [netuid, get_hotkey_pub_ss58(wallet)]
)
if uid is None:
return NeuronInfo.get_null_neuron()
Expand Down Expand Up @@ -525,7 +526,7 @@ async def get_neuron_for_pubkey_and_subnet():
if not Confirm.ask(
f"Continue Registration?\n"
f" hotkey [{COLOR_PALETTE.G.HK}]({wallet.hotkey_str})[/{COLOR_PALETTE.G.HK}]:"
f"\t[{COLOR_PALETTE.G.HK}]{wallet.hotkey.ss58_address}[/{COLOR_PALETTE.G.HK}]\n"
f"\t[{COLOR_PALETTE.G.HK}]{get_hotkey_pub_ss58(wallet)}[/{COLOR_PALETTE.G.HK}]\n"
f" coldkey [{COLOR_PALETTE.G.CK}]({wallet.name})[/{COLOR_PALETTE.G.CK}]:"
f"\t[{COLOR_PALETTE.G.CK}]{wallet.coldkeypub.ss58_address}[/{COLOR_PALETTE.G.CK}]\n"
f" network:\t\t[{COLOR_PALETTE.G.LINKS}]{subtensor.network}[/{COLOR_PALETTE.G.LINKS}]\n"
Expand Down Expand Up @@ -577,7 +578,7 @@ async def get_neuron_for_pubkey_and_subnet():
if not pow_result:
# might be registered already on this subnet
is_registered = await is_hotkey_registered(
subtensor, netuid=netuid, hotkey_ss58=wallet.hotkey.ss58_address
subtensor, netuid=netuid, hotkey_ss58=get_hotkey_pub_ss58(wallet)
)
if is_registered:
err_console.print(
Expand All @@ -598,7 +599,7 @@ async def get_neuron_for_pubkey_and_subnet():
"block_number": pow_result.block_number,
"nonce": pow_result.nonce,
"work": [int(byte_) for byte_ in pow_result.seal],
"hotkey": wallet.hotkey.ss58_address,
"hotkey": get_hotkey_pub_ss58(wallet),
"coldkey": wallet.coldkeypub.ss58_address,
},
)
Expand Down Expand Up @@ -639,7 +640,7 @@ async def get_neuron_for_pubkey_and_subnet():
is_registered = await is_hotkey_registered(
subtensor,
netuid=netuid,
hotkey_ss58=wallet.hotkey.ss58_address,
hotkey_ss58=get_hotkey_pub_ss58(wallet),
)
if is_registered:
console.print(
Expand Down Expand Up @@ -704,7 +705,7 @@ async def burned_register_extrinsic(
spinner="aesthetic",
) as status:
my_uid = await subtensor.query(
"SubtensorModule", "Uids", [netuid, wallet.hotkey.ss58_address]
"SubtensorModule", "Uids", [netuid, get_hotkey_pub_ss58(wallet)]
)
block_hash = await subtensor.substrate.get_chain_head()

Expand Down Expand Up @@ -751,7 +752,7 @@ async def burned_register_extrinsic(
call_function="burned_register",
call_params={
"netuid": netuid,
"hotkey": wallet.hotkey.ss58_address,
"hotkey": get_hotkey_pub_ss58(wallet),
},
)
success, err_msg = await subtensor.sign_and_send_extrinsic(
Expand All @@ -773,10 +774,10 @@ async def burned_register_extrinsic(
reuse_block=False,
),
subtensor.get_netuids_for_hotkey(
wallet.hotkey.ss58_address, block_hash=block_hash
get_hotkey_pub_ss58(wallet), block_hash=block_hash
),
subtensor.query(
"SubtensorModule", "Uids", [netuid, wallet.hotkey.ss58_address]
"SubtensorModule", "Uids", [netuid, get_hotkey_pub_ss58(wallet)]
),
)

Expand Down Expand Up @@ -1146,7 +1147,7 @@ async def _block_solver(

timeout = 0.15 if cuda else 0.15
while netuid == -1 or not await is_hotkey_registered(
subtensor, netuid, wallet.hotkey.ss58_address
subtensor, netuid, get_hotkey_pub_ss58(wallet)
):
# Wait until a solver finds a solution
try:
Expand Down Expand Up @@ -1755,37 +1756,39 @@ async def swap_hotkey_extrinsic(
:return: Success
"""
block_hash = await subtensor.substrate.get_chain_head()
hk_ss58 = get_hotkey_pub_ss58(wallet)
netuids_registered = await subtensor.get_netuids_for_hotkey(
wallet.hotkey.ss58_address, block_hash=block_hash
hk_ss58, block_hash=block_hash
)
netuids_registered_new_hotkey = await subtensor.get_netuids_for_hotkey(
new_wallet.hotkey.ss58_address, block_hash=block_hash
hk_ss58, block_hash=block_hash
)

if netuid is not None and netuid not in netuids_registered:
err_console.print(
f":cross_mark: [red]Failed[/red]: Original hotkey {wallet.hotkey.ss58_address} is not registered on subnet {netuid}"
f":cross_mark: [red]Failed[/red]: Original hotkey {hk_ss58} is not registered on subnet {netuid}"
)
return False

elif not len(netuids_registered) > 0:
err_console.print(
f"Original hotkey [dark_orange]{wallet.hotkey.ss58_address}[/dark_orange] is not registered on any subnet. "
f"Original hotkey [dark_orange]{hk_ss58}[/dark_orange] is not registered on any subnet. "
f"Please register and try again"
)
return False

new_hk_ss58 = get_hotkey_pub_ss58(new_wallet)
if netuid is not None:
if netuid in netuids_registered_new_hotkey:
err_console.print(
f":cross_mark: [red]Failed[/red]: New hotkey {new_wallet.hotkey.ss58_address} "
f":cross_mark: [red]Failed[/red]: New hotkey {new_hk_ss58} "
f"is already registered on subnet {netuid}"
)
return False
else:
if len(netuids_registered_new_hotkey) > 0:
err_console.print(
f":cross_mark: [red]Failed[/red]: New hotkey {new_wallet.hotkey.ss58_address} "
f":cross_mark: [red]Failed[/red]: New hotkey {new_hk_ss58} "
f"is already registered on subnet(s) {netuids_registered_new_hotkey}"
)
return False
Expand All @@ -1798,28 +1801,28 @@ async def swap_hotkey_extrinsic(
if netuid is not None:
confirm_message = (
f"Do you want to swap [dark_orange]{wallet.name}[/dark_orange] hotkey \n\t"
f"[dark_orange]{wallet.hotkey.ss58_address} ({wallet.hotkey_str})[/dark_orange] with hotkey \n\t"
f"[dark_orange]{new_wallet.hotkey.ss58_address} ({new_wallet.hotkey_str})[/dark_orange] on subnet {netuid}\n"
f"[dark_orange]{hk_ss58} ({wallet.hotkey_str})[/dark_orange] with hotkey \n\t"
f"[dark_orange]{new_hk_ss58} ({new_wallet.hotkey_str})[/dark_orange] on subnet {netuid}\n"
"This operation will cost [bold cyan]1 TAO (recycled)[/bold cyan]"
)
else:
confirm_message = (
f"Do you want to swap [dark_orange]{wallet.name}[/dark_orange] hotkey \n\t"
f"[dark_orange]{wallet.hotkey.ss58_address} ({wallet.hotkey_str})[/dark_orange] with hotkey \n\t"
f"[dark_orange]{new_wallet.hotkey.ss58_address} ({new_wallet.hotkey_str})[/dark_orange] on all subnets\n"
f"[dark_orange]{hk_ss58} ({wallet.hotkey_str})[/dark_orange] with hotkey \n\t"
f"[dark_orange]{new_hk_ss58} ({new_wallet.hotkey_str})[/dark_orange] on all subnets\n"
"This operation will cost [bold cyan]1 TAO (recycled)[/bold cyan]"
)

if not Confirm.ask(confirm_message):
return False
print_verbose(
f"Swapping {wallet.name}'s hotkey ({wallet.hotkey.ss58_address} - {wallet.hotkey_str}) with "
f"{new_wallet.name}'s hotkey ({new_wallet.hotkey.ss58_address} - {new_wallet.hotkey_str})"
f"Swapping {wallet.name}'s hotkey ({hk_ss58} - {wallet.hotkey_str}) with "
f"{new_wallet.name}'s hotkey ({new_hk_ss58} - {new_wallet.hotkey_str})"
)
with console.status(":satellite: Swapping hotkeys...", spinner="aesthetic"):
call_params = {
"hotkey": wallet.hotkey.ss58_address,
"new_hotkey": new_wallet.hotkey.ss58_address,
"hotkey": hk_ss58,
"new_hotkey": new_hk_ss58,
"netuid": netuid,
}

Expand All @@ -1832,7 +1835,8 @@ async def swap_hotkey_extrinsic(

if success:
console.print(
f"Hotkey {wallet.hotkey.ss58_address} ({wallet.hotkey_str}) swapped for new hotkey: {new_wallet.hotkey.ss58_address} ({new_wallet.hotkey_str})"
f"Hotkey {hk_ss58} ({wallet.hotkey_str}) swapped for new hotkey: "
f"{new_hk_ss58} ({new_wallet.hotkey_str})"
)
return True
else:
Expand Down
Loading
Loading