Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update infrastructure commands: sync-validator, sync-web3signer, upda… #20

Merged
merged 4 commits into from
Mar 16, 2023
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
107 changes: 0 additions & 107 deletions key_manager/commands/cleanup_keys.py

This file was deleted.

102 changes: 55 additions & 47 deletions key_manager/commands/create_keys.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import json
from multiprocessing import Pool
from os import makedirs, path
from pathlib import Path

import click
Expand All @@ -6,11 +9,7 @@
from sw_utils import get_execution_client

from key_manager.contrib import async_command, greenify
from key_manager.credentials import (
export_deposit_data_json,
export_keystores,
generate_credentials,
)
from key_manager.credentials import Credential, CredentialManager
from key_manager.execution import generate_vault_address
from key_manager.password import get_or_create_password_file
from key_manager.settings import AVAILABLE_NETWORKS, GOERLI, NETWORKS, VAULT_TYPE
Expand All @@ -19,7 +18,6 @@
validate_eth_address,
validate_mnemonic,
)
from key_manager.web3signer import Web3signer


@click.option(
Expand Down Expand Up @@ -98,12 +96,6 @@
default='./data/keystores/password.txt',
type=click.Path(exists=False, file_okay=True, dir_okay=False),
)
@click.option(
'--web3signer-endpoint',
required=False,
help='The endpoint of the web3signer service for uploading the keystores.',
type=str,
)
@click.option(
'--mnemonic-start-index',
required=False,
Expand All @@ -123,12 +115,6 @@
type=click.Path(exists=False, file_okay=True, dir_okay=False),
default='./mnemonic_next_index.txt',
)
@click.option(
'--no-confirm',
is_flag=True,
default=False,
help='Skips confirmation messages when provided.',
)
@click.command(help='Creates the validator keys from the mnemonic.')
@async_command
async def create_keys(
Expand All @@ -142,10 +128,8 @@ async def create_keys(
deposit_data_file: str,
keystores: str,
password_file: str,
web3signer_endpoint: str,
mnemonic_start_index: int | None,
mnemonic_next_index_file: str,
no_confirm: bool,
) -> None:
if not vault and admin and vault_type and execution_endpoint:
execution_client = get_execution_client(execution_endpoint, is_poa=NETWORKS[network].IS_POA)
Expand Down Expand Up @@ -176,47 +160,71 @@ async def create_keys(
with open(mnemonic_next_index_file, 'r', encoding='utf-8') as f:
mnemonic_start_index = int(f.read())

credentials = await generate_credentials(
credentials = CredentialManager.generate_credentials(
network=network,
vault=vault,
mnemonic=mnemonic,
count=count,
start_index=mnemonic_start_index,
)
deposit_data = export_deposit_data_json(credentials=credentials, filename=deposit_data_file)
deposit_data = _export_deposit_data_json(credentials=credentials, filename=deposit_data_file)

export_keystores(credentials=credentials, keystores_dir=keystores, password_file=password_file)
_export_keystores(credentials=credentials, keystores_dir=keystores, password_file=password_file)

with open(mnemonic_next_index_file, 'w', encoding='utf-8') as f:
f.write(str(mnemonic_start_index + count))

if web3signer_endpoint:
if not no_confirm:
click.confirm(
f'Generated {count} keystores, upload them to the Web3Signer?',
default=True,
abort=True,
)
password = get_or_create_password_file(password_file)
keys = []
with click.progressbar(
credentials,
label='Uploading keystores to web3signer\t\t',
show_percent=False,
show_pos=True,
) as _credentials:
for credential in _credentials:
keys.append(credential.encrypt_signing_keystore(password).as_json())
Web3signer(web3signer_endpoint).upload_keys(
keystores=keys,
passwords=[password] * len(keys),
)

click.clear()

click.echo(
f'Done. Generated {greenify(count)} keys for {greenify(vault)} vault.\n'
f'Keystores saved to {greenify(keystores)} file\n'
f'Deposit data saved to {greenify(deposit_data)} file\n'
f'Next mnemonic start index saved to {greenify(mnemonic_next_index_file)} file',
)


def _export_deposit_data_json(credentials: list[Credential], filename: str) -> str:
with click.progressbar(
length=len(credentials),
label='Generating deposit data JSON\t\t',
show_percent=False,
show_pos=True,
) as bar, Pool() as pool:
results = [
pool.apply_async(
cred.deposit_datum_dict,
callback=lambda x: bar.update(1),
)
for cred in credentials
]
for result in results:
result.wait()
deposit_data = [result.get() for result in results]

makedirs(path.dirname(path.abspath(filename)), exist_ok=True)
with open(filename, 'w', encoding='utf-8') as f:
json.dump(deposit_data, f, default=lambda x: x.hex())
return filename


def _export_keystores(
credentials: list[Credential], keystores_dir: str, password_file: str
) -> None:
makedirs(path.abspath(keystores_dir), exist_ok=True)
password = get_or_create_password_file(password_file)
with click.progressbar(
credentials,
label='Exporting validator keystores\t\t',
show_percent=False,
show_pos=True,
) as bar, Pool() as pool:
results = [
pool.apply_async(
cred.save_signing_keystore,
kwds=dict(password=password, folder=keystores_dir),
callback=lambda x: bar.update(1),
)
for cred in credentials
]

for result in results:
result.wait()
23 changes: 21 additions & 2 deletions key_manager/commands/create_wallet.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
import json
import time
from os import path

import click
from eth_account import Account

from key_manager.contrib import greenify
from key_manager.credentials import generate_encrypted_wallet
from key_manager.password import get_or_create_password_file
from key_manager.validators import validate_empty_dir, validate_mnemonic


Expand All @@ -22,5 +27,19 @@
)
@click.command(help='Creates the encrypted hot wallet from the mnemonic.')
def create_wallet(mnemonic: str, wallet_dir: str) -> None:
wallet = generate_encrypted_wallet(mnemonic, wallet_dir)
wallet = _generate_encrypted_wallet(mnemonic, wallet_dir)
click.echo(f'Done. Wallet {greenify(wallet)} saved to {greenify(wallet_dir)} directory')


def _generate_encrypted_wallet(mnemonic: str, wallet_dir: str) -> str:
Account.enable_unaudited_hdwallet_features()

account = Account().from_mnemonic(mnemonic=mnemonic)
password = get_or_create_password_file(path.join(wallet_dir, 'password.txt'))
encrypted_data = Account.encrypt(account.key, password=password)

wallet_name = f'{account.address}-{int(time.time())}.json'
with open(path.join(wallet_dir, wallet_name), 'w', encoding='utf-8') as f:
json.dump(encrypted_data, f, default=lambda x: x.hex())

return wallet_name
Loading