staking-deposit-cli/eth2deposit/cli/generate_keys.py
2020-11-13 00:25:11 +08:00

130 lines
4.8 KiB
Python

import os
import click
from typing import (
Any,
Callable,
)
from eth2deposit.credentials import (
CredentialList,
)
from eth2deposit.exceptions import ValidationError
from eth2deposit.utils.validation import (
verify_deposit_data_json,
validate_password_strength,
)
from eth2deposit.utils.constants import (
MAX_DEPOSIT_AMOUNT,
DEFAULT_VALIDATOR_KEYS_FOLDER_NAME,
)
from eth2deposit.utils.ascii_art import RHINO_0
from eth2deposit.settings import (
ALL_CHAINS,
MAINNET,
get_chain_setting,
)
def get_password(text: str) -> str:
return click.prompt(text, hide_input=True, show_default=False, type=str)
def validate_password(cts: click.Context, param: Any, password: str) -> str:
is_valid_password = False
# The given password has passed confirmation
try:
validate_password_strength(password)
except ValidationError as e:
click.echo(f'Error: {e} Please retype.')
else:
is_valid_password = True
while not is_valid_password:
password = get_password(text='Type the password that secures your validator keystore(s)')
try:
validate_password_strength(password)
except ValidationError as e:
click.echo(f'Error: {e} Please retype.')
else:
# Confirm password
password_confirmation = get_password(text='Repeat for confirmation')
if password == password_confirmation:
is_valid_password = True
else:
click.echo('Error: the two entered values do not match. Please retype again.')
return password
def generate_keys_arguments_decorator(function: Callable[..., Any]) -> Callable[..., Any]:
'''
This is a decorator that, when applied to a parent-command, implements the
to obtain the necessary arguments for the generate_keys() subcommand.
'''
decorators = [
click.option(
'--num_validators',
prompt='Please choose how many validators you wish to run',
help='The number of validators keys you want to generate (you can always generate more later)',
required=True,
type=click.IntRange(0, 2**32 - 1),
),
click.option(
'--folder',
default=os.getcwd(),
help='The folder to place the generated keystores and deposit_data.json in',
type=click.Path(exists=True, file_okay=False, dir_okay=True),
),
click.option(
'--chain',
default=MAINNET,
help='The version of eth2 you are targeting. use "mainnet" if you are depositing ETH',
prompt='Please choose the (mainnet or testnet) network/chain name',
type=click.Choice(ALL_CHAINS.keys(), case_sensitive=False),
),
click.password_option(
'--keystore_password',
callback=validate_password,
help=('The password that will secure your keystores. You will need to re-enter this to decrypt them when '
'you setup your eth2 validators. (It is reccomened not to use this argument, and wait for the CLI '
'to ask you for your mnemonic as otherwise it will appear in your shell history.)'),
prompt='Type the password that secures your validator keystore(s)',
),
]
for decorator in reversed(decorators):
function = decorator(function)
return function
@click.command()
@click.pass_context
def generate_keys(ctx: click.Context, validator_start_index: int,
num_validators: int, folder: str, chain: str, keystore_password: str, **kwargs: Any) -> None:
mnemonic = ctx.obj['mnemonic']
mnemonic_password = ctx.obj['mnemonic_password']
amounts = [MAX_DEPOSIT_AMOUNT] * num_validators
folder = os.path.join(folder, DEFAULT_VALIDATOR_KEYS_FOLDER_NAME)
chain_setting = get_chain_setting(chain)
if not os.path.exists(folder):
os.mkdir(folder)
click.clear()
click.echo(RHINO_0)
click.echo('Creating your keys.')
credentials = CredentialList.from_mnemonic(
mnemonic=mnemonic,
mnemonic_password=mnemonic_password,
num_keys=num_validators,
amounts=amounts,
chain_setting=chain_setting,
start_index=validator_start_index,
)
keystore_filefolders = credentials.export_keystores(password=keystore_password, folder=folder)
deposits_file = credentials.export_deposit_data_json(folder=folder)
if not credentials.verify_keystores(keystore_filefolders=keystore_filefolders, password=keystore_password):
raise ValidationError("Failed to verify the keystores.")
if not verify_deposit_data_json(deposits_file):
raise ValidationError("Failed to verify the deposit data JSON files.")
click.echo('\nSuccess!\nYour keys can be found at: %s' % folder)
click.pause('\n\nPress any key.')