Support multiple BLS implementations (#1335)

## Issue Addressed

NA

## Proposed Changes

- Refactor the `bls` crate to support multiple BLS "backends" (e.g., milagro, blst, etc).
- Removes some duplicate, unused code in `common/rest_types/src/validator.rs`.
- Removes the old "upgrade legacy keypairs" functionality (these were unencrypted keys that haven't been supported for a few testnets, no one should be using them anymore).

## Additional Info

Most of the files changed are just inconsequential changes to function names.

## TODO

- [x] Optimization levels
- [x] Infinity point: https://github.com/supranational/blst/issues/11
- [x] Ensure milagro *and* blst are tested via CI
- [x] What to do with unsafe code?
- [x] Test infinity point in signature sets
This commit is contained in:
Paul Hauner
2020-07-25 02:03:18 +00:00
parent 21bcc8848d
commit b73c497be2
117 changed files with 3009 additions and 2463 deletions

View File

@@ -1,5 +1,4 @@
mod common;
pub mod upgrade_legacy_keypairs;
pub mod validator;
pub mod wallet;
@@ -19,7 +18,6 @@ pub fn cli_app<'a, 'b>() -> App<'a, 'b> {
.about("Utilities for generating and managing Ethereum 2.0 accounts.")
.subcommand(wallet::cli_app())
.subcommand(validator::cli_app())
.subcommand(upgrade_legacy_keypairs::cli_app())
}
/// Run the account manager, returning an error if the operation did not succeed.
@@ -27,7 +25,6 @@ pub fn run<T: EthSpec>(matches: &ArgMatches<'_>, env: Environment<T>) -> Result<
match matches.subcommand() {
(wallet::CMD, Some(matches)) => wallet::cli_run(matches)?,
(validator::CMD, Some(matches)) => validator::cli_run(matches, env)?,
(upgrade_legacy_keypairs::CMD, Some(matches)) => upgrade_legacy_keypairs::cli_run(matches)?,
(unknown, _) => {
return Err(format!(
"{} is not a valid {} command. See --help.",

View File

@@ -1,149 +0,0 @@
//! This command allows migrating from the old method of storing keys (unencrypted SSZ) to the
//! current method of using encrypted EIP-2335 keystores.
//!
//! This command should be completely removed once the `unencrypted_keys` feature is removed from
//! the `validator_dir` command. This should hopefully be in mid-June 2020.
//!
//! ## Example
//!
//! This command will upgrade all keypairs in the `--validators-dir`, storing the newly-generated
//! passwords in `--secrets-dir`.
//!
//! ```ignore
//! lighthouse am upgrade-legacy-keypairs \
//! --validators-dir ~/.lighthouse/validators \
//! --secrets-dir ~/.lighthouse/secrets
//! ```
use crate::{SECRETS_DIR_FLAG, VALIDATOR_DIR_FLAG};
use clap::{App, Arg, ArgMatches};
use clap_utils::parse_required;
use eth2_keystore::KeystoreBuilder;
use rand::{distributions::Alphanumeric, Rng};
use std::fs::{create_dir_all, read_dir, write, File};
use std::path::{Path, PathBuf};
use types::Keypair;
use validator_dir::{
unencrypted_keys::load_unencrypted_keypair, VOTING_KEYSTORE_FILE, WITHDRAWAL_KEYSTORE_FILE,
};
pub const CMD: &str = "upgrade-legacy-keypairs";
pub const VOTING_KEYPAIR_FILE: &str = "voting_keypair";
pub const WITHDRAWAL_KEYPAIR_FILE: &str = "withdrawal_keypair";
pub fn cli_app<'a, 'b>() -> App<'a, 'b> {
App::new(CMD)
.about(
"Converts legacy unencrypted SSZ keypairs into encrypted keystores.",
)
.arg(
Arg::with_name(VALIDATOR_DIR_FLAG)
.long(VALIDATOR_DIR_FLAG)
.value_name("VALIDATORS_DIRECTORY")
.takes_value(true)
.required(true)
.help("The directory containing legacy validators. Generally ~/.lighthouse/validators"),
)
.arg(
Arg::with_name(SECRETS_DIR_FLAG)
.long(SECRETS_DIR_FLAG)
.value_name("SECRETS_DIRECTORY")
.takes_value(true)
.required(true)
.help("The directory where keystore passwords will be stored. Generally ~/.lighthouse/secrets"),
)
}
pub fn cli_run(matches: &ArgMatches) -> Result<(), String> {
let validators_dir: PathBuf = parse_required(matches, VALIDATOR_DIR_FLAG)?;
let secrets_dir: PathBuf = parse_required(matches, SECRETS_DIR_FLAG)?;
if !secrets_dir.exists() {
create_dir_all(&secrets_dir)
.map_err(|e| format!("Failed to create secrets dir {:?}: {:?}", secrets_dir, e))?;
}
read_dir(&validators_dir)
.map_err(|e| {
format!(
"Failed to read validators directory {:?}: {:?}",
validators_dir, e
)
})?
.try_for_each(|dir| {
let path = dir
.map_err(|e| format!("Unable to read dir: {}", e))?
.path();
if path.is_dir() {
if let Err(e) = upgrade_keypair(
&path,
&secrets_dir,
VOTING_KEYPAIR_FILE,
VOTING_KEYSTORE_FILE,
) {
println!("Validator {:?}: {:?}", path, e);
} else {
println!("Validator {:?} voting keys: success", path);
}
if let Err(e) = upgrade_keypair(
&path,
&secrets_dir,
WITHDRAWAL_KEYPAIR_FILE,
WITHDRAWAL_KEYSTORE_FILE,
) {
println!("Validator {:?}: {:?}", path, e);
} else {
println!("Validator {:?} withdrawal keys: success", path);
}
}
Ok(())
})
}
fn upgrade_keypair<P: AsRef<Path>>(
validator_dir: P,
secrets_dir: P,
input_filename: &str,
output_filename: &str,
) -> Result<(), String> {
let validator_dir = validator_dir.as_ref();
let secrets_dir = secrets_dir.as_ref();
let keypair: Keypair = load_unencrypted_keypair(validator_dir.join(input_filename))?;
let password = rand::thread_rng()
.sample_iter(&Alphanumeric)
.take(48)
.collect::<String>()
.into_bytes();
let keystore = KeystoreBuilder::new(&keypair, &password, "".into())
.map_err(|e| format!("Unable to create keystore builder: {:?}", e))?
.build()
.map_err(|e| format!("Unable to build keystore: {:?}", e))?;
let keystore_path = validator_dir.join(output_filename);
if keystore_path.exists() {
return Err(format!("{:?} already exists", keystore_path));
}
let mut file = File::create(&keystore_path).map_err(|e| format!("Cannot create: {:?}", e))?;
keystore
.to_json_writer(&mut file)
.map_err(|e| format!("Cannot write keystore to {:?}: {:?}", keystore_path, e))?;
let password_path = secrets_dir.join(keypair.pk.as_hex_string());
if password_path.exists() {
return Err(format!("{:?} already exists", password_path));
}
write(&password_path, &password)
.map_err(|e| format!("Unable to write password to {:?}: {:?}", password_path, e))?;
Ok(())
}