mirror of
https://github.com/sigp/lighthouse.git
synced 2026-05-08 17:26:04 +00:00
Start adding import validator testing
This commit is contained in:
1
Cargo.lock
generated
1
Cargo.lock
generated
@@ -7378,6 +7378,7 @@ dependencies = [
|
|||||||
"tokio",
|
"tokio",
|
||||||
"tree_hash",
|
"tree_hash",
|
||||||
"types",
|
"types",
|
||||||
|
"validator_client",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|||||||
@@ -56,6 +56,7 @@ pub struct ApiTester {
|
|||||||
pub initialized_validators: Arc<RwLock<InitializedValidators>>,
|
pub initialized_validators: Arc<RwLock<InitializedValidators>>,
|
||||||
pub validator_store: Arc<ValidatorStore<TestingSlotClock, E>>,
|
pub validator_store: Arc<ValidatorStore<TestingSlotClock, E>>,
|
||||||
pub url: SensitiveUrl,
|
pub url: SensitiveUrl,
|
||||||
|
pub api_token: String,
|
||||||
pub test_runtime: TestRuntime,
|
pub test_runtime: TestRuntime,
|
||||||
pub _server_shutdown: oneshot::Sender<()>,
|
pub _server_shutdown: oneshot::Sender<()>,
|
||||||
pub _validator_dir: TempDir,
|
pub _validator_dir: TempDir,
|
||||||
@@ -116,7 +117,7 @@ impl ApiTester {
|
|||||||
|
|
||||||
let context = Arc::new(Context {
|
let context = Arc::new(Context {
|
||||||
task_executor: test_runtime.task_executor.clone(),
|
task_executor: test_runtime.task_executor.clone(),
|
||||||
api_secret,
|
api_secret: api_secret,
|
||||||
validator_dir: Some(validator_dir.path().into()),
|
validator_dir: Some(validator_dir.path().into()),
|
||||||
validator_store: Some(validator_store.clone()),
|
validator_store: Some(validator_store.clone()),
|
||||||
spec: E::default_spec(),
|
spec: E::default_spec(),
|
||||||
@@ -146,13 +147,14 @@ impl ApiTester {
|
|||||||
))
|
))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let client = ValidatorClientHttpClient::new(url.clone(), api_pubkey).unwrap();
|
let client = ValidatorClientHttpClient::new(url.clone(), api_pubkey.clone()).unwrap();
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
client,
|
client,
|
||||||
initialized_validators,
|
initialized_validators,
|
||||||
validator_store,
|
validator_store,
|
||||||
url,
|
url,
|
||||||
|
api_token: api_pubkey,
|
||||||
test_runtime,
|
test_runtime,
|
||||||
_server_shutdown: shutdown_tx,
|
_server_shutdown: shutdown_tx,
|
||||||
_validator_dir: validator_dir,
|
_validator_dir: validator_dir,
|
||||||
|
|||||||
@@ -27,3 +27,4 @@ tempfile = "3.1.0"
|
|||||||
tokio = { version = "1.14.0", features = ["time", "rt-multi-thread", "macros"] }
|
tokio = { version = "1.14.0", features = ["time", "rt-multi-thread", "macros"] }
|
||||||
regex = "1.6.0"
|
regex = "1.6.0"
|
||||||
eth2_network_config = { path = "../common/eth2_network_config" }
|
eth2_network_config = { path = "../common/eth2_network_config" }
|
||||||
|
validator_client = { path = "../validator_client" }
|
||||||
|
|||||||
@@ -70,8 +70,38 @@ pub fn cli_app<'a, 'b>() -> App<'a, 'b> {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct ImportConfig {
|
||||||
|
validators_file_path: PathBuf,
|
||||||
|
vc_url: SensitiveUrl,
|
||||||
|
vc_token_path: PathBuf,
|
||||||
|
ignore_duplicates: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ImportConfig {
|
||||||
|
fn from_cli(matches: &ArgMatches) -> Result<Self, String> {
|
||||||
|
Ok(Self {
|
||||||
|
validators_file_path: clap_utils::parse_required(matches, VALIDATORS_FILE_FLAG)?,
|
||||||
|
vc_url: clap_utils::parse_required(matches, VALIDATOR_CLIENT_URL_FLAG)?,
|
||||||
|
vc_token_path: clap_utils::parse_required(matches, VALIDATOR_CLIENT_TOKEN_FLAG)?,
|
||||||
|
ignore_duplicates: matches.is_present(IGNORE_DUPLICATES_FLAG),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn cli_run<'a>(matches: &'a ArgMatches<'a>) -> Result<(), String> {
|
pub async fn cli_run<'a>(matches: &'a ArgMatches<'a>) -> Result<(), String> {
|
||||||
let validators_file_path: PathBuf = clap_utils::parse_required(matches, VALIDATORS_FILE_FLAG)?;
|
let config = ImportConfig::from_cli(matches)?;
|
||||||
|
run(config).await
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn run<'a>(config: ImportConfig) -> Result<(), String> {
|
||||||
|
let ImportConfig {
|
||||||
|
validators_file_path,
|
||||||
|
vc_url,
|
||||||
|
vc_token_path,
|
||||||
|
ignore_duplicates,
|
||||||
|
} = config;
|
||||||
|
|
||||||
if !validators_file_path.exists() {
|
if !validators_file_path.exists() {
|
||||||
return Err(format!("Unable to find file at {:?}", validators_file_path));
|
return Err(format!("Unable to find file at {:?}", validators_file_path));
|
||||||
}
|
}
|
||||||
@@ -81,35 +111,23 @@ pub async fn cli_run<'a>(matches: &'a ArgMatches<'a>) -> Result<(), String> {
|
|||||||
.create(false)
|
.create(false)
|
||||||
.open(&validators_file_path)
|
.open(&validators_file_path)
|
||||||
.map_err(|e| format!("Unable to open {:?}: {:?}", validators_file_path, e))?;
|
.map_err(|e| format!("Unable to open {:?}: {:?}", validators_file_path, e))?;
|
||||||
let validators = serde_json::from_reader(&validators_file).map_err(|e| {
|
let validators: Vec<ValidatorSpecification> = serde_json::from_reader(&validators_file)
|
||||||
|
.map_err(|e| {
|
||||||
format!(
|
format!(
|
||||||
"Unable to parse JSON in {:?}: {:?}",
|
"Unable to parse JSON in {:?}: {:?}",
|
||||||
validators_file_path, e
|
validators_file_path, e
|
||||||
)
|
)
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
import_validators(matches, validators).await
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn import_validators<'a>(
|
|
||||||
matches: &'a ArgMatches<'a>,
|
|
||||||
validators: Vec<ValidatorSpecification>,
|
|
||||||
) -> Result<(), String> {
|
|
||||||
let count = validators.len();
|
let count = validators.len();
|
||||||
|
|
||||||
let vc_url: Option<SensitiveUrl> =
|
let http_client = {
|
||||||
clap_utils::parse_optional(matches, VALIDATOR_CLIENT_URL_FLAG)?;
|
|
||||||
let vc_token_path: Option<PathBuf> =
|
|
||||||
clap_utils::parse_optional(matches, VALIDATOR_CLIENT_TOKEN_FLAG)?;
|
|
||||||
|
|
||||||
let http_client = match (vc_url, vc_token_path) {
|
|
||||||
(Some(vc_url), Some(vc_token_path)) => {
|
|
||||||
let token_bytes = fs::read(&vc_token_path)
|
let token_bytes = fs::read(&vc_token_path)
|
||||||
.map_err(|e| format!("Failed to read {:?}: {:?}", vc_token_path, e))?;
|
.map_err(|e| format!("Failed to read {:?}: {:?}", vc_token_path, e))?;
|
||||||
let token_string = String::from_utf8(token_bytes)
|
let token_string = String::from_utf8(token_bytes)
|
||||||
.map_err(|e| format!("Failed to parse {:?} as utf8: {:?}", vc_token_path, e))?;
|
.map_err(|e| format!("Failed to parse {:?} as utf8: {:?}", vc_token_path, e))?;
|
||||||
let http_client = ValidatorClientHttpClient::new(vc_url.clone(), token_string)
|
let http_client =
|
||||||
.map_err(|e| {
|
ValidatorClientHttpClient::new(vc_url.clone(), token_string).map_err(|e| {
|
||||||
format!(
|
format!(
|
||||||
"Could not instantiate HTTP client from URL and secret: {:?}",
|
"Could not instantiate HTTP client from URL and secret: {:?}",
|
||||||
e
|
e
|
||||||
@@ -127,17 +145,9 @@ pub async fn import_validators<'a>(
|
|||||||
remote_keystores.data.len()
|
remote_keystores.data.len()
|
||||||
);
|
);
|
||||||
|
|
||||||
Some(http_client)
|
http_client
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
return Err(format!(
|
|
||||||
"Inconsistent use of {} and {}",
|
|
||||||
VALIDATOR_CLIENT_URL_FLAG, VALIDATOR_CLIENT_TOKEN_FLAG
|
|
||||||
))
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(http_client) = http_client {
|
|
||||||
eprintln!(
|
eprintln!(
|
||||||
"Starting to submit validators {} to VC, each validator may take several seconds",
|
"Starting to submit validators {} to VC, each validator may take several seconds",
|
||||||
count
|
count
|
||||||
@@ -156,9 +166,7 @@ pub async fn import_validators<'a>(
|
|||||||
|
|
||||||
let voting_public_key = voting_keystore
|
let voting_public_key = voting_keystore
|
||||||
.public_key()
|
.public_key()
|
||||||
.ok_or_else(|| {
|
.ok_or_else(|| format!("Validator keystore at index {} is missing a public key", i))?
|
||||||
format!("Validator keystore at index {} is missing a public key", i)
|
|
||||||
})?
|
|
||||||
.into();
|
.into();
|
||||||
|
|
||||||
let request = ImportKeystoresRequest {
|
let request = ImportKeystoresRequest {
|
||||||
@@ -210,7 +218,48 @@ pub async fn import_validators<'a>(
|
|||||||
|
|
||||||
eprintln!("Uploaded keystore {} of {} to the VC", i + 1, count);
|
eprintln!("Uploaded keystore {} of {} to the VC", i + 1, count);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
use std::fs;
|
||||||
|
use tempfile::{tempdir, TempDir};
|
||||||
|
use validator_client::http_api::test_utils::ApiTester;
|
||||||
|
|
||||||
|
const VALIDATORS_FILE_NAME: &str = "validators.json";
|
||||||
|
const VC_TOKEN_FILE_NAME: &str = "vc_token.json";
|
||||||
|
|
||||||
|
struct TestBuilder {
|
||||||
|
config: ImportConfig,
|
||||||
|
vc: ApiTester,
|
||||||
|
dir: TempDir,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TestBuilder {
|
||||||
|
async fn new() -> Self {
|
||||||
|
let dir = tempdir().unwrap();
|
||||||
|
let vc = ApiTester::new().await;
|
||||||
|
let vc_token_path = dir.path().join(VC_TOKEN_FILE_NAME);
|
||||||
|
fs::write(&vc_token_path, &vc.api_token).unwrap();
|
||||||
|
|
||||||
|
Self {
|
||||||
|
config: ImportConfig {
|
||||||
|
validators_file_path: dir.path().join(VALIDATORS_FILE_NAME),
|
||||||
|
vc_url: vc.url.clone(),
|
||||||
|
vc_token_path,
|
||||||
|
ignore_duplicates: false,
|
||||||
|
},
|
||||||
|
vc,
|
||||||
|
dir,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn blah() {
|
||||||
|
TestBuilder::new().await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user