From 5cc2c132efdb19421eaa4aee886fb981a10d3360 Mon Sep 17 00:00:00 2001 From: Mac L Date: Fri, 23 Aug 2024 04:04:27 +1000 Subject: [PATCH] Fix ui endpoint --- validator_client/src/beacon_node_fallback.rs | 48 +++++++++++++++++--- validator_client/src/http_api/mod.rs | 34 ++++++++------ validator_client/src/notifier.rs | 8 ++-- 3 files changed, 66 insertions(+), 24 deletions(-) diff --git a/validator_client/src/beacon_node_fallback.rs b/validator_client/src/beacon_node_fallback.rs index cf3f6c71f5..514e364210 100644 --- a/validator_client/src/beacon_node_fallback.rs +++ b/validator_client/src/beacon_node_fallback.rs @@ -11,7 +11,7 @@ use crate::http_metrics::metrics::{inc_counter_vec, ENDPOINT_ERRORS, ENDPOINT_RE use environment::RuntimeContext; use eth2::BeaconNodeHttpClient; use futures::future; -use serde::{Deserialize, Serialize}; +use serde::{ser::SerializeStruct, Deserialize, Serialize, Serializer}; use slog::{debug, error, warn, Logger}; use slot_clock::SlotClock; use std::cmp::Ordering; @@ -138,11 +138,47 @@ pub enum CandidateError { TimeDiscrepancy, } -#[derive(Debug, Clone)] +impl std::fmt::Display for CandidateError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + CandidateError::PreGenesis => write!(f, "PreGenesis"), + CandidateError::Uninitialized => write!(f, "Uninitialized"), + CandidateError::Offline => write!(f, "Offline"), + CandidateError::Incompatible => write!(f, "Incompatible"), + CandidateError::TimeDiscrepancy => write!(f, "TimeDiscrepancy"), + } + } +} + +#[derive(Debug, Clone, Deserialize)] pub struct CandidateInfo { pub index: usize, - pub node: String, - pub health: Option, + pub endpoint: String, + pub health: Result, +} + +impl Serialize for CandidateInfo { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + let mut state = serializer.serialize_struct("CandidateInfo", 2)?; + + state.serialize_field("index", &self.index)?; + state.serialize_field("endpoint", &self.endpoint)?; + + // Serialize either the health or the error field based on the Result + match &self.health { + Ok(health) => { + state.serialize_field("health", health)?; + } + Err(e) => { + state.serialize_field("error", &e.to_string())?; + } + } + + state.end() + } } /// Represents a `BeaconNodeHttpClient` inside a `BeaconNodeFallback` that may or may not be used @@ -417,8 +453,8 @@ impl BeaconNodeFallback { candidate_info.push(CandidateInfo { index: candidate.index, - node: candidate.beacon_node.to_string(), - health: health.ok(), + endpoint: candidate.beacon_node.to_string(), + health, }); } diff --git a/validator_client/src/http_api/mod.rs b/validator_client/src/http_api/mod.rs index 950d4f9f04..cffbcd62a5 100644 --- a/validator_client/src/http_api/mod.rs +++ b/validator_client/src/http_api/mod.rs @@ -8,8 +8,7 @@ mod tests; pub mod test_utils; -use crate::beacon_node_fallback::CandidateError; -use crate::beacon_node_health::BeaconNodeHealth; +use crate::beacon_node_fallback::CandidateInfo; use crate::http_api::graffiti::{delete_graffiti, get_graffiti, set_graffiti}; use crate::http_api::create_signed_voluntary_exit::create_signed_voluntary_exit; @@ -419,21 +418,28 @@ pub fn serve( .and(warp::path::end()) .and(block_service_filter.clone()) .then(|block_filter: BlockService| async move { - let mut result: HashMap<(usize, String), Result> = - HashMap::new(); + let mut result: HashMap> = HashMap::new(); + + let mut beacon_nodes = Vec::new(); for node in &*block_filter.beacon_nodes.candidates.read().await { - result.insert( - (node.index, node.beacon_node.to_string()), - *node.health.read().await, - ); + beacon_nodes.push(CandidateInfo { + index: node.index, + endpoint: node.beacon_node.to_string(), + health: *node.health.read().await, + }); } - if let Some(proposer_nodes) = &block_filter.proposer_nodes { - for node in &*proposer_nodes.candidates.read().await { - result.insert( - (node.index, node.beacon_node.to_string()), - *node.health.read().await, - ); + result.insert("beacon_nodes".to_string(), beacon_nodes); + + if let Some(proposer_nodes_list) = &block_filter.proposer_nodes { + let mut proposer_nodes = Vec::new(); + for node in &*proposer_nodes_list.candidates.read().await { + proposer_nodes.push(CandidateInfo { + index: node.index, + endpoint: node.beacon_node.to_string(), + health: *node.health.read().await, + }); } + result.insert("proposer_nodes".to_string(), proposer_nodes); } blocking_json_task(move || Ok(api_types::GenericResponse::from(result))).await diff --git a/validator_client/src/notifier.rs b/validator_client/src/notifier.rs index 1e524ceae8..00d7b14de7 100644 --- a/validator_client/src/notifier.rs +++ b/validator_client/src/notifier.rs @@ -59,7 +59,7 @@ async fn notify( if num_synced > 0 { let primary = candidate_info .first() - .map(|candidate| candidate.node.as_str()) + .map(|candidate| candidate.endpoint.as_str()) .unwrap_or("None"); info!( log, @@ -85,13 +85,13 @@ async fn notify( } for info in candidate_info { - if let Some(health) = info.health { + if let Ok(health) = info.health { debug!( log, "Beacon node info"; "status" => "Connected", "index" => info.index, - "endpoint" => info.node, + "endpoint" => info.endpoint, "head_slot" => %health.head, "is_optimistic" => ?health.optimistic_status, "execution_engine_status" => ?health.execution_status, @@ -103,7 +103,7 @@ async fn notify( "Beacon node info"; "status" => "Disconnected", "index" => info.index, - "endpoint" => info.node, + "endpoint" => info.endpoint, ); } }