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) setting = get_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, fork_version=setting.GENESIS_FORK_VERSION, 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.')
def main(num_validators: int, mnemonic_language: str, folder: str, chain: str, password: str) -> None: check_python_version() mnemonic = generate_mnemonic(mnemonic_language, WORD_LISTS_PATH) amounts = [MAX_DEPOSIT_AMOUNT] * num_validators folder = os.path.join(folder, DEFAULT_VALIDATOR_KEYS_FOLDER_NAME) setting = get_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, num_keys=num_validators, amounts=amounts, fork_version=setting.GENESIS_FORK_VERSION, ) click.echo('Saving your keystore(s).') keystore_filefolders = credentials.export_keystores(password=password, folder=folder) click.echo('Creating your deposit(s).') deposits_file = credentials.export_deposit_data_json(folder=folder) click.echo('Verifying your keystore(s).') if not credentials.verify_keystores( keystore_filefolders=keystore_filefolders, password=password): raise ValidationError("Failed to verify the keystores.") click.echo('Verifying your deposit(s).') 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.')
def validate_withdrawal_credentials(withdrawal_credentials: str) -> bytes: try: decoded_withdrawal_credentials = bytes.fromhex(withdrawal_credentials) except Exception: raise ValueError( "Wrong withdrawal_credentials value. Is it HEX (not Base64) format?" ) if len(decoded_withdrawal_credentials) != 32: raise ValidationError( "Wrong withdrawal_credentials length. Must be 32 bytes (64 hex symbols)." ) if decoded_withdrawal_credentials[:1] != BLS_WITHDRAWAL_PREFIX: raise ValidationError("Wrong withdrawal_credentials format.") return decoded_withdrawal_credentials
def __init__(self, *, mnemonic: str, mnemonic_password: str, index: int, amount: int, chain_setting: BaseChainSetting, withdrawal_pk: str, withdrawal_credentials: str): # Set path as EIP-2334 format # https://eips.ethereum.org/EIPS/eip-2334 purpose = '12381' coin_type = '3600' account = str(index) withdrawal_key_path = f'm/{purpose}/{coin_type}/{account}/0' self.signing_key_path = f'{withdrawal_key_path}/0' if withdrawal_pk and withdrawal_credentials: raise ValidationError( "Simultaneous use of withdrawal_credentials and withdrawal_pk is incompatible. Use only one of them." ) if withdrawal_pk: self.custom_withdrawal_pk = validate_withdrawal_pk( withdrawal_pk=withdrawal_pk) else: self.custom_withdrawal_pk = None if withdrawal_credentials: self.custom_withdrawal_credentials = validate_withdrawal_credentials( withdrawal_credentials=withdrawal_credentials) else: self.custom_withdrawal_credentials = None self.withdrawal_sk = mnemonic_and_path_to_key( mnemonic=mnemonic, path=withdrawal_key_path, password=mnemonic_password) self.signing_sk = mnemonic_and_path_to_key(mnemonic=mnemonic, path=self.signing_key_path, password=mnemonic_password) self.amount = amount self.chain_setting = chain_setting
def deposit_message(self) -> DepositMessage: if not MIN_DEPOSIT_AMOUNT <= self.amount <= MAX_DEPOSIT_AMOUNT: raise ValidationError( f"{self.amount / ETH2GWEI} ETH deposits are not within the bounds of this cli." ) return DepositMessage( pubkey=self.signing_pk, withdrawal_credentials=self.withdrawal_credentials, amount=self.amount, )
def validate_withdrawal_pk(withdrawal_pk: str) -> bytes: try: decoded_withdrawal_pk = bytes.fromhex(withdrawal_pk) except Exception: raise ValueError( "Wrong withdrawal_pk value. Is it HEX (not Base64) format?") if len(decoded_withdrawal_pk) != 48: raise ValidationError( "Wrong withdrawal_pk length. Must be 48 bytes (96 hex symbols).") return decoded_withdrawal_pk
def validate_mnemonic(cts: click.Context, param: Any, mnemonic: str) -> str: if verify_mnemonic(mnemonic, WORD_LISTS_PATH): return mnemonic else: raise ValidationError( 'That is not a valid mnemonic, please check for typos.')
def validate_password_strength(password: str) -> None: if len(password) < 8: raise ValidationError( f"The password length should be at least 8. Got {len(password)}.")