Add lcli command to replace state pubkeys (#1999)

## Issue Addressed

NA

## Proposed Changes

Adds a command to replace all the pubkeys in a state with one generated from a mnemonic.

## Additional Info

This is not production code, it's only for testing.
This commit is contained in:
Paul Hauner 2021-01-19 08:42:30 +00:00
parent 805e152f66
commit 46cb6e204c
4 changed files with 91 additions and 0 deletions

2
Cargo.lock generated
View File

@ -3324,6 +3324,7 @@ dependencies = [
name = "lcli"
version = "1.0.6"
dependencies = [
"account_utils",
"bls",
"clap",
"clap_utils",
@ -3335,6 +3336,7 @@ dependencies = [
"eth2_libp2p",
"eth2_network_config",
"eth2_ssz",
"eth2_wallet",
"futures 0.3.8",
"genesis",
"hex",

View File

@ -35,4 +35,6 @@ rand = "0.7.3"
eth2_keystore = { path = "../crypto/eth2_keystore" }
lighthouse_version = { path = "../common/lighthouse_version" }
directory = { path = "../common/directory" }
account_utils = { path = "../common/account_utils" }
eth2_wallet = { path = "../crypto/eth2_wallet" }
tokio-compat-02 = "0.1"

View File

@ -8,6 +8,7 @@ mod insecure_validators;
mod interop_genesis;
mod new_testnet;
mod parse_hex;
mod replace_state_pubkeys;
mod skip_slots;
mod transition_blocks;
@ -231,6 +232,35 @@ fn main() {
.help("The value for state.genesis_time."),
),
)
.subcommand(
SubCommand::with_name("replace-state-pubkeys")
.about(
"Loads a file with an SSZ-encoded BeaconState and replaces \
all the validator pubkeys with ones derived from the mnemonic \
such that validator indices correspond to EIP-2334 voting keypair \
derivation paths.",
)
.arg(
Arg::with_name("ssz-state")
.index(1)
.value_name("PATH")
.takes_value(true)
.required(true)
.help("The path to the SSZ file"),
)
.arg(
Arg::with_name("mnemonic")
.index(2)
.value_name("BIP39_MNENMONIC")
.takes_value(true)
.required(true)
.default_value(
"replace nephew blur decorate waste convince soup column \
orient excite play baby",
)
.help("The mnemonic for key derivation."),
),
)
.subcommand(
SubCommand::with_name("new-testnet")
.about(
@ -516,6 +546,8 @@ fn run<T: EthSpec>(
.map_err(|e| format!("Failed to run interop-genesis command: {}", e)),
("change-genesis-time", Some(matches)) => change_genesis_time::run::<T>(matches)
.map_err(|e| format!("Failed to run change-genesis-time command: {}", e)),
("replace-state-pubkeys", Some(matches)) => replace_state_pubkeys::run::<T>(matches)
.map_err(|e| format!("Failed to run replace-state-pubkeys command: {}", e)),
("new-testnet", Some(matches)) => new_testnet::run::<T>(matches)
.map_err(|e| format!("Failed to run new_testnet command: {}", e)),
("check-deposit-data", Some(matches)) => check_deposit_data::run::<T>(matches)

View File

@ -0,0 +1,55 @@
use account_utils::{eth2_keystore::keypair_from_secret, mnemonic_from_phrase};
use clap::ArgMatches;
use eth2_wallet::bip39::Seed;
use eth2_wallet::{recover_validator_secret_from_mnemonic, KeyType};
use ssz::{Decode, Encode};
use std::fs::File;
use std::io::{Read, Write};
use std::path::PathBuf;
use types::{BeaconState, EthSpec};
pub fn run<T: EthSpec>(matches: &ArgMatches) -> Result<(), String> {
let path = matches
.value_of("ssz-state")
.ok_or("ssz-state not specified")?
.parse::<PathBuf>()
.map_err(|e| format!("Unable to parse ssz-state: {}", e))?;
let mnemonic_phrase = matches
.value_of("mnemonic")
.ok_or("mnemonic not specified")?;
let mut state: BeaconState<T> = {
let mut file = File::open(&path).map_err(|e| format!("Unable to open file: {}", e))?;
let mut ssz = vec![];
file.read_to_end(&mut ssz)
.map_err(|e| format!("Unable to read file: {}", e))?;
BeaconState::from_ssz_bytes(&ssz).map_err(|e| format!("Unable to decode SSZ: {:?}", e))?
};
let mnemonic = mnemonic_from_phrase(mnemonic_phrase)?;
let seed = Seed::new(&mnemonic, "");
for (index, validator) in state.validators.iter_mut().enumerate() {
let (secret, _) =
recover_validator_secret_from_mnemonic(seed.as_bytes(), index as u32, KeyType::Voting)
.map_err(|e| format!("Unable to generate validator key: {:?}", e))?;
let keypair = keypair_from_secret(secret.as_bytes())
.map_err(|e| format!("Unable build keystore: {:?}", e))?;
eprintln!("{}: {}", index, keypair.pk);
validator.pubkey = keypair.pk.into();
}
let mut file = File::create(path).map_err(|e| format!("Unable to create file: {}", e))?;
file.write_all(&state.as_ssz_bytes())
.map_err(|e| format!("Unable to write to file: {}", e))?;
Ok(())
}