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:
parent
805e152f66
commit
46cb6e204c
2
Cargo.lock
generated
2
Cargo.lock
generated
@ -3324,6 +3324,7 @@ dependencies = [
|
|||||||
name = "lcli"
|
name = "lcli"
|
||||||
version = "1.0.6"
|
version = "1.0.6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"account_utils",
|
||||||
"bls",
|
"bls",
|
||||||
"clap",
|
"clap",
|
||||||
"clap_utils",
|
"clap_utils",
|
||||||
@ -3335,6 +3336,7 @@ dependencies = [
|
|||||||
"eth2_libp2p",
|
"eth2_libp2p",
|
||||||
"eth2_network_config",
|
"eth2_network_config",
|
||||||
"eth2_ssz",
|
"eth2_ssz",
|
||||||
|
"eth2_wallet",
|
||||||
"futures 0.3.8",
|
"futures 0.3.8",
|
||||||
"genesis",
|
"genesis",
|
||||||
"hex",
|
"hex",
|
||||||
|
@ -35,4 +35,6 @@ rand = "0.7.3"
|
|||||||
eth2_keystore = { path = "../crypto/eth2_keystore" }
|
eth2_keystore = { path = "../crypto/eth2_keystore" }
|
||||||
lighthouse_version = { path = "../common/lighthouse_version" }
|
lighthouse_version = { path = "../common/lighthouse_version" }
|
||||||
directory = { path = "../common/directory" }
|
directory = { path = "../common/directory" }
|
||||||
|
account_utils = { path = "../common/account_utils" }
|
||||||
|
eth2_wallet = { path = "../crypto/eth2_wallet" }
|
||||||
tokio-compat-02 = "0.1"
|
tokio-compat-02 = "0.1"
|
||||||
|
@ -8,6 +8,7 @@ mod insecure_validators;
|
|||||||
mod interop_genesis;
|
mod interop_genesis;
|
||||||
mod new_testnet;
|
mod new_testnet;
|
||||||
mod parse_hex;
|
mod parse_hex;
|
||||||
|
mod replace_state_pubkeys;
|
||||||
mod skip_slots;
|
mod skip_slots;
|
||||||
mod transition_blocks;
|
mod transition_blocks;
|
||||||
|
|
||||||
@ -231,6 +232,35 @@ fn main() {
|
|||||||
.help("The value for state.genesis_time."),
|
.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(
|
||||||
SubCommand::with_name("new-testnet")
|
SubCommand::with_name("new-testnet")
|
||||||
.about(
|
.about(
|
||||||
@ -516,6 +546,8 @@ fn run<T: EthSpec>(
|
|||||||
.map_err(|e| format!("Failed to run interop-genesis command: {}", e)),
|
.map_err(|e| format!("Failed to run interop-genesis command: {}", e)),
|
||||||
("change-genesis-time", Some(matches)) => change_genesis_time::run::<T>(matches)
|
("change-genesis-time", Some(matches)) => change_genesis_time::run::<T>(matches)
|
||||||
.map_err(|e| format!("Failed to run change-genesis-time command: {}", e)),
|
.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)
|
("new-testnet", Some(matches)) => new_testnet::run::<T>(matches)
|
||||||
.map_err(|e| format!("Failed to run new_testnet command: {}", e)),
|
.map_err(|e| format!("Failed to run new_testnet command: {}", e)),
|
||||||
("check-deposit-data", Some(matches)) => check_deposit_data::run::<T>(matches)
|
("check-deposit-data", Some(matches)) => check_deposit_data::run::<T>(matches)
|
||||||
|
55
lcli/src/replace_state_pubkeys.rs
Normal file
55
lcli/src/replace_state_pubkeys.rs
Normal 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(())
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user