diff --git a/coral-cli/src/commands/validator/list_keys.rs b/coral-cli/src/commands/validator/list_keys.rs new file mode 100644 index 0000000..b553ec7 --- /dev/null +++ b/coral-cli/src/commands/validator/list_keys.rs @@ -0,0 +1,90 @@ +use axum::http::StatusCode; + +use puffersecuresigner::client::traits::ValidatorClientTrait; +use puffersecuresigner::client::ClientBuilder; + +use coral_lib::error::ServerErrorResponse; +use coral_lib::error::{AppError, AppErrorKind, AppResult}; +use serde::Deserialize; + +#[derive(Clone, Debug, Deserialize)] +pub struct Keystore { + pub pubkey: String, +} + +pub async fn list_keys( + disable_enclave: bool, + keystore_path: Option, + enclave_url: Option, +) -> AppResult { + if disable_enclave { + let keystore_path = match keystore_path { + Some(path) => path, + None => { + return Err(AppError::new( + AppErrorKind::ParseError, + "keystore-path is required when disable-enclave is set".to_string(), + )); + } + }; + + let mut dirlist: Vec = std::fs::read_dir(keystore_path)? + .filter_map(|entry| entry.ok()) + .collect(); + dirlist.sort_by_key(|dir| dir.path()); + for (i, entry) in dirlist.iter().enumerate() { + let file_bytes = std::fs::read(entry.path())?; + let keystore: Keystore = serde_json::from_slice(&file_bytes)?; + println!("{i}: {}", keystore.pubkey); + } + + Ok(0) + } else { + let enclave_url = match enclave_url { + Some(url) => url, + None => { + return Err(AppError::new( + AppErrorKind::ParseError, + "enclave-url is required when disable-enclave is not set".to_string(), + )); + } + }; + + println!("================"); + println!("Enclave URL: '{}'", enclave_url); + println!("================"); + + println!("Running enclave health check..."); + let enclave_client = ClientBuilder::new() + .validator_url(enclave_url.to_string()) + .build(); + let health_status = enclave_client.validator.health().await; + + let validator_enclave_client = enclave_client.validator; + + if !health_status { + let err = AppError::new( + AppErrorKind::EnclaveError, + "Health check failed".to_string(), + ); + return Err(err); + } + + println!("Calling enclave..."); + + let keys_result = validator_enclave_client + .list_bls_keys() + .await + .map_err(|err| { + let error_msg = "Failed to list_bls_keys"; + tracing::error!("{error_msg}"); + tracing::error!("{err}"); + ServerErrorResponse::new(StatusCode::INTERNAL_SERVER_ERROR, 1000, error_msg) + })?; + + for (i, key) in keys_result.data.iter().enumerate() { + println!("{i}: {}", key.pubkey); + } + Ok(0) + } +} diff --git a/coral-cli/src/commands/validator/mod.rs b/coral-cli/src/commands/validator/mod.rs index 17550d3..05cc588 100644 --- a/coral-cli/src/commands/validator/mod.rs +++ b/coral-cli/src/commands/validator/mod.rs @@ -1,3 +1,4 @@ +pub mod list_keys; pub mod register_validator; use std::path::PathBuf; @@ -12,6 +13,10 @@ pub enum ValidatorCommand { ListKeys { #[arg(long = "disable-enclave")] disable_enclave: bool, + #[arg(long = "keystore-path")] + keystore_path: Option, + #[arg(long = "enclave-url")] + enclave_url: Option, }, #[command(about = "Register a validator into Puffer's Pool")] Register { @@ -40,8 +45,12 @@ pub enum ValidatorCommand { impl ValidatorCommand { pub async fn execute(self) -> AppResult { match self { - Self::ListKeys { .. } => { - println!("TODO"); + Self::ListKeys { + disable_enclave, + keystore_path, + enclave_url, + } => { + list_keys::list_keys(disable_enclave, keystore_path, enclave_url).await?; } Self::Register { guardian_pubkeys,