## Proposed Changes Split out several crates which now exist in separate repos under `sigp`. - [`ssz` and `ssz_derive`](https://github.com/sigp/ethereum_ssz) - [`tree_hash` and `tree_hash_derive`](https://github.com/sigp/tree_hash) - [`ethereum_hashing`](https://github.com/sigp/ethereum_hashing) - [`ethereum_serde_utils`](https://github.com/sigp/ethereum_serde_utils) - [`ssz_types`](https://github.com/sigp/ssz_types) For the published crates see: https://crates.io/teams/github:sigp:crates-io?sort=recent-updates. ## Additional Info - [x] Need to work out how to handle versioning. I was hoping to do 1.0 versions of several crates, but if they depend on `ethereum-types 0.x` that is not going to work. EDIT: decided to go with 0.5.x versions. - [x] Need to port several changes from `tree-states`, `capella`, `eip4844` branches to the external repos.
258 lines
8.6 KiB
Rust
258 lines
8.6 KiB
Rust
use beacon_chain::{
|
|
validator_monitor::HISTORIC_EPOCHS, BeaconChain, BeaconChainError, BeaconChainTypes,
|
|
};
|
|
use eth2::types::{Epoch, ValidatorStatus};
|
|
use serde::{Deserialize, Serialize};
|
|
use std::collections::{HashMap, HashSet};
|
|
use std::sync::Arc;
|
|
use warp_utils::reject::beacon_chain_error;
|
|
|
|
#[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)]
|
|
pub struct ValidatorCountResponse {
|
|
pub active_ongoing: u64,
|
|
pub active_exiting: u64,
|
|
pub active_slashed: u64,
|
|
pub pending_initialized: u64,
|
|
pub pending_queued: u64,
|
|
pub withdrawal_possible: u64,
|
|
pub withdrawal_done: u64,
|
|
pub exited_unslashed: u64,
|
|
pub exited_slashed: u64,
|
|
}
|
|
|
|
pub fn get_validator_count<T: BeaconChainTypes>(
|
|
chain: Arc<BeaconChain<T>>,
|
|
) -> Result<ValidatorCountResponse, warp::Rejection> {
|
|
let spec = &chain.spec;
|
|
let mut active_ongoing = 0;
|
|
let mut active_exiting = 0;
|
|
let mut active_slashed = 0;
|
|
let mut pending_initialized = 0;
|
|
let mut pending_queued = 0;
|
|
let mut withdrawal_possible = 0;
|
|
let mut withdrawal_done = 0;
|
|
let mut exited_unslashed = 0;
|
|
let mut exited_slashed = 0;
|
|
|
|
chain
|
|
.with_head(|head| {
|
|
let state = &head.beacon_state;
|
|
let epoch = state.current_epoch();
|
|
for validator in state.validators() {
|
|
let status =
|
|
ValidatorStatus::from_validator(validator, epoch, spec.far_future_epoch);
|
|
|
|
match status {
|
|
ValidatorStatus::ActiveOngoing => active_ongoing += 1,
|
|
ValidatorStatus::ActiveExiting => active_exiting += 1,
|
|
ValidatorStatus::ActiveSlashed => active_slashed += 1,
|
|
ValidatorStatus::PendingInitialized => pending_initialized += 1,
|
|
ValidatorStatus::PendingQueued => pending_queued += 1,
|
|
ValidatorStatus::WithdrawalPossible => withdrawal_possible += 1,
|
|
ValidatorStatus::WithdrawalDone => withdrawal_done += 1,
|
|
ValidatorStatus::ExitedUnslashed => exited_unslashed += 1,
|
|
ValidatorStatus::ExitedSlashed => exited_slashed += 1,
|
|
// Since we are not invoking `superset`, all other variants will be 0.
|
|
_ => (),
|
|
}
|
|
}
|
|
Ok::<(), BeaconChainError>(())
|
|
})
|
|
.map_err(beacon_chain_error)?;
|
|
|
|
Ok(ValidatorCountResponse {
|
|
active_ongoing,
|
|
active_exiting,
|
|
active_slashed,
|
|
pending_initialized,
|
|
pending_queued,
|
|
withdrawal_possible,
|
|
withdrawal_done,
|
|
exited_unslashed,
|
|
exited_slashed,
|
|
})
|
|
}
|
|
|
|
#[derive(PartialEq, Serialize, Deserialize)]
|
|
pub struct ValidatorInfoRequestData {
|
|
#[serde(with = "serde_utils::quoted_u64_vec")]
|
|
indices: Vec<u64>,
|
|
}
|
|
|
|
#[derive(PartialEq, Serialize, Deserialize)]
|
|
pub struct ValidatorInfoValues {
|
|
#[serde(with = "serde_utils::quoted_u64")]
|
|
epoch: u64,
|
|
#[serde(with = "serde_utils::quoted_u64")]
|
|
total_balance: u64,
|
|
}
|
|
|
|
#[derive(PartialEq, Serialize, Deserialize)]
|
|
pub struct ValidatorInfo {
|
|
info: Vec<ValidatorInfoValues>,
|
|
}
|
|
|
|
#[derive(PartialEq, Serialize, Deserialize)]
|
|
pub struct ValidatorInfoResponse {
|
|
validators: HashMap<String, ValidatorInfo>,
|
|
}
|
|
|
|
pub fn get_validator_info<T: BeaconChainTypes>(
|
|
request_data: ValidatorInfoRequestData,
|
|
chain: Arc<BeaconChain<T>>,
|
|
) -> Result<ValidatorInfoResponse, warp::Rejection> {
|
|
let current_epoch = chain.epoch().map_err(beacon_chain_error)?;
|
|
|
|
let epochs = current_epoch.saturating_sub(HISTORIC_EPOCHS).as_u64()..=current_epoch.as_u64();
|
|
|
|
let validator_ids = chain
|
|
.validator_monitor
|
|
.read()
|
|
.get_all_monitored_validators()
|
|
.iter()
|
|
.cloned()
|
|
.collect::<HashSet<String>>();
|
|
|
|
let indices = request_data
|
|
.indices
|
|
.iter()
|
|
.map(|index| index.to_string())
|
|
.collect::<HashSet<String>>();
|
|
|
|
let ids = validator_ids
|
|
.intersection(&indices)
|
|
.collect::<HashSet<&String>>();
|
|
|
|
let mut validators = HashMap::new();
|
|
|
|
for id in ids {
|
|
if let Ok(index) = id.parse::<u64>() {
|
|
if let Some(validator) = chain
|
|
.validator_monitor
|
|
.read()
|
|
.get_monitored_validator(index)
|
|
{
|
|
let mut info = vec![];
|
|
for epoch in epochs.clone() {
|
|
if let Some(total_balance) = validator.get_total_balance(Epoch::new(epoch)) {
|
|
info.push(ValidatorInfoValues {
|
|
epoch,
|
|
total_balance,
|
|
});
|
|
}
|
|
}
|
|
validators.insert(id.clone(), ValidatorInfo { info });
|
|
}
|
|
}
|
|
}
|
|
|
|
Ok(ValidatorInfoResponse { validators })
|
|
}
|
|
|
|
#[derive(PartialEq, Serialize, Deserialize)]
|
|
pub struct ValidatorMetricsRequestData {
|
|
indices: Vec<u64>,
|
|
}
|
|
|
|
#[derive(PartialEq, Serialize, Deserialize)]
|
|
pub struct ValidatorMetrics {
|
|
attestation_hits: u64,
|
|
attestation_misses: u64,
|
|
attestation_hit_percentage: f64,
|
|
attestation_head_hits: u64,
|
|
attestation_head_misses: u64,
|
|
attestation_head_hit_percentage: f64,
|
|
attestation_target_hits: u64,
|
|
attestation_target_misses: u64,
|
|
attestation_target_hit_percentage: f64,
|
|
latest_attestation_inclusion_distance: u64,
|
|
}
|
|
|
|
#[derive(PartialEq, Serialize, Deserialize)]
|
|
pub struct ValidatorMetricsResponse {
|
|
validators: HashMap<String, ValidatorMetrics>,
|
|
}
|
|
|
|
pub fn post_validator_monitor_metrics<T: BeaconChainTypes>(
|
|
request_data: ValidatorMetricsRequestData,
|
|
chain: Arc<BeaconChain<T>>,
|
|
) -> Result<ValidatorMetricsResponse, warp::Rejection> {
|
|
let validator_ids = chain
|
|
.validator_monitor
|
|
.read()
|
|
.get_all_monitored_validators()
|
|
.iter()
|
|
.cloned()
|
|
.collect::<HashSet<String>>();
|
|
|
|
let indices = request_data
|
|
.indices
|
|
.iter()
|
|
.map(|index| index.to_string())
|
|
.collect::<HashSet<String>>();
|
|
|
|
let ids = validator_ids
|
|
.intersection(&indices)
|
|
.collect::<HashSet<&String>>();
|
|
|
|
let mut validators = HashMap::new();
|
|
|
|
for id in ids {
|
|
if let Ok(index) = id.parse::<u64>() {
|
|
if let Some(validator) = chain
|
|
.validator_monitor
|
|
.read()
|
|
.get_monitored_validator(index)
|
|
{
|
|
let val_metrics = validator.metrics.read();
|
|
let attestation_hits = val_metrics.attestation_hits;
|
|
let attestation_misses = val_metrics.attestation_misses;
|
|
let attestation_head_hits = val_metrics.attestation_head_hits;
|
|
let attestation_head_misses = val_metrics.attestation_head_misses;
|
|
let attestation_target_hits = val_metrics.attestation_target_hits;
|
|
let attestation_target_misses = val_metrics.attestation_target_misses;
|
|
let latest_attestation_inclusion_distance =
|
|
val_metrics.latest_attestation_inclusion_distance;
|
|
drop(val_metrics);
|
|
|
|
let attestations = attestation_hits + attestation_misses;
|
|
let attestation_hit_percentage: f64 = if attestations == 0 {
|
|
0.0
|
|
} else {
|
|
(100 * attestation_hits / attestations) as f64
|
|
};
|
|
let head_attestations = attestation_head_hits + attestation_head_misses;
|
|
let attestation_head_hit_percentage: f64 = if head_attestations == 0 {
|
|
0.0
|
|
} else {
|
|
(100 * attestation_head_hits / head_attestations) as f64
|
|
};
|
|
|
|
let target_attestations = attestation_target_hits + attestation_target_misses;
|
|
let attestation_target_hit_percentage: f64 = if target_attestations == 0 {
|
|
0.0
|
|
} else {
|
|
(100 * attestation_target_hits / target_attestations) as f64
|
|
};
|
|
|
|
let metrics = ValidatorMetrics {
|
|
attestation_hits,
|
|
attestation_misses,
|
|
attestation_hit_percentage,
|
|
attestation_head_hits,
|
|
attestation_head_misses,
|
|
attestation_head_hit_percentage,
|
|
attestation_target_hits,
|
|
attestation_target_misses,
|
|
attestation_target_hit_percentage,
|
|
latest_attestation_inclusion_distance,
|
|
};
|
|
|
|
validators.insert(id.clone(), metrics);
|
|
}
|
|
}
|
|
}
|
|
|
|
Ok(ValidatorMetricsResponse { validators })
|
|
}
|