chia-blockchain/src/cmds/keys.py

244 lines
6.8 KiB
Python

from pathlib import Path
from blspy import PrivateKey, ExtendedPrivateKey
from src.cmds.init import check_keys
from src.util.keychain import (
generate_mnemonic,
bytes_to_mnemonic,
Keychain,
seed_from_mnemonic,
)
command_list = [
"generate",
"generate_and_print",
"show",
"add_seed",
"add",
"add_not_extended",
"delete",
"delete_all",
]
def help_message():
print("usage: chia keys command")
print(f"command can be any of {command_list}")
print("")
print("chia keys generate (generates and adds a key to keychain)")
print("chia keys generate_and_print (generates but does NOT add to keychain)")
print("chia keys show (displays all the keys in keychain)")
print("chia keys add_seed -m [24 words] (add a private key through the mnemonic)")
print("chia keys add -k [extended key] (add an extended private key in hex form)")
print(
"chia keys add_not_extended -k [key] (add a not extended private key in hex form)"
)
print(
"chia keys delete -f [fingerprint] (delete a key by it's pk fingerprint in hex form)"
)
print("chia keys delete_all (delete all private keys in keychain)")
def make_parser(parser):
parser.add_argument(
"-m",
"--mnemonic",
type=str,
nargs=24,
default=None,
help="Enter mnemonic you want to use",
)
parser.add_argument(
"-k", "--key", type=str, default=None, help="Enter the raw private key in hex",
)
parser.add_argument(
"-f",
"--fingerprint",
type=int,
default=None,
help="Enter the fingerprint of the key you want to delete",
)
parser.add_argument(
"command",
help=f"Command can be any one of {command_list}",
type=str,
nargs="?",
)
parser.set_defaults(function=handler)
parser.print_help = lambda self=parser: help_message()
keychain: Keychain = Keychain()
def generate_and_print():
"""
Generates a seed for a private key, and prints the mnemonic to the terminal.
"""
mnemonic = generate_mnemonic()
mnemonics_string = mnemonic_to_string(mnemonic)
print("Generating private key. Mnemonic:")
print(mnemonics_string)
print(
"Note that this key has not been added to the keychain. Run chia keys add_seed -m [MNEMONICS] to add"
)
return mnemonic
def generate_and_add():
"""
Generates a seed for a private key, prints the mnemonic to the terminal, and adds the key to the keyring.
"""
mnemonic = generate_mnemonic()
print("Generating private key.")
add_private_key_seed(mnemonic)
def add_private_key_seed(mnemonic):
"""
Add a private key seed to the keyring, with the given mnemonic.
"""
try:
seed = seed_from_mnemonic(mnemonic)
fingerprint = (
ExtendedPrivateKey.from_seed(seed).get_public_key().get_fingerprint()
)
print(
f"Adding private key with public key fingerprint {fingerprint} and mnemonic"
)
print(f"{mnemonic_to_string(mnemonic)}")
keychain.add_private_key_seed(seed)
except ValueError as e:
print(e)
return
def add_private_key(args):
"""
Adds a private key to the keyring, without a seed (with the raw private key bytes).
"""
if args.key is None:
print("Please specify the key argument -k")
quit()
key_hex = args.key
assert key_hex is not None
extended_key = ExtendedPrivateKey.from_bytes(bytes.fromhex(key_hex))
print(
f"Adding private_key: {extended_key} with fingerprint {extended_key.get_public_key().get_fingerprint()}"
)
keychain.add_private_key(extended_key)
def add_private_key_not_extended(args):
"""
Adds a not extended private key to the keyring. This can be used for migrating old pool sks from keys.yaml.
"""
if args.key is None:
print("Please specify the key argument -k")
quit()
key_hex = args.key
assert key_hex
private_key = PrivateKey.from_bytes(bytes.fromhex(key_hex))
print(
f"Adding private_key: {private_key} with fingerprint {private_key.get_public_key().get_fingerprint()}"
)
keychain.add_private_key_not_extended(private_key)
def mnemonic_to_string(mnemonic):
"""
Converts a menmonic to a user readable string in the terminal.
"""
mnemonics_string = ""
for i in range(0, 24):
mnemonics_string += f"{i + 1}) {mnemonic[i]}"
if i != 23:
mnemonics_string += ", "
if (i + 1) % 6 == 0:
mnemonics_string += "\n"
return mnemonics_string
def show_all_keys():
"""
Prints all keys and mnemonics (if available).
"""
private_keys = keychain.get_all_private_keys()
if len(private_keys) == 0:
print("There are no saved private keys.")
return
print("Showing all private keys:")
for sk, seed in private_keys:
print("")
print("Fingerprint:", sk.get_public_key().get_fingerprint())
print("Extended private key:", bytes(sk).hex())
if seed is not None:
mnemonic = bytes_to_mnemonic(seed)
mnemonic_string = mnemonic_to_string(mnemonic)
print("Mnemonic seed:")
print(mnemonic_string)
else:
print(
"There is no mnemonic for this key, since it was imported without a seed. (Or migrated from keys.yaml)."
)
def delete(args):
"""
Delete a key by it's public key fingerprint (which is an int).
"""
if args.fingerprint is None:
print("Please specify the fingerprint argument -f")
quit()
fingerprint = args.fingerprint
assert fingerprint is not None
print(f"Deleting private_key with fingerprint {fingerprint}")
keychain.delete_key_by_fingerprint(fingerprint)
def handler(args, parser):
if args.command is None or len(args.command) < 1:
help_message()
parser.exit(1)
root_path: Path = args.root_path
if not root_path.is_dir():
raise RuntimeError(
"Please initialize (or migrate) your config directory with chia init."
)
command = args.command
if command not in command_list:
help_message()
parser.exit(1)
if command == "generate":
generate_and_add()
check_keys(root_path)
elif command == "show":
show_all_keys()
elif command == "add_seed":
add_private_key_seed(args.mnemonic)
check_keys(root_path)
elif command == "add":
add_private_key(args)
check_keys(root_path)
elif command == "add_not_extended":
add_private_key_not_extended(args)
check_keys(root_path)
elif command == "delete":
delete(args)
check_keys(root_path)
elif command == "delete_all":
keychain.delete_all_keys()
if command == "generate_and_print":
generate_and_print()