use std::cmp::Reverse;
use casper_types::Timestamp;
use crate::{
components::consensus::{
highway_core::{
highway::Highway,
state::{Fault, State},
},
traits::Context,
utils::ValidatorIndex,
},
utils::div_round,
};
#[derive(Copy, Clone, Debug, Ord, PartialOrd, Eq, PartialEq)]
enum Status {
LastSeenSecondsAgo(u64),
Inactive,
EquivocatedInOtherEra,
Equivocated,
}
impl Status {
fn for_index<C: Context>(
idx: ValidatorIndex,
state: &State<C>,
now: Timestamp,
) -> Option<Status> {
if let Some(fault) = state.maybe_fault(idx) {
return Some(match fault {
Fault::Banned | Fault::Indirect => Status::EquivocatedInOtherEra,
Fault::Direct(_) => Status::Equivocated,
});
}
if state.panorama()[idx].is_none() {
return Some(Status::Inactive);
}
if state
.last_seen(idx)
.saturating_add(state.params().max_round_length())
< now
{
let seconds = now.saturating_diff(state.last_seen(idx)).millis() / 1000;
return Some(Status::LastSeenSecondsAgo(seconds));
}
None
}
}
#[derive(Debug)]
#[allow(dead_code)]
pub(crate) struct Participation<C>
where
C: Context,
{
instance_id: C::InstanceId,
faulty_stake_percent: u8,
inactive_stake_percent: u8,
inactive_validators: Vec<(ValidatorIndex, C::ValidatorId, Status)>,
faulty_validators: Vec<(ValidatorIndex, C::ValidatorId, Status)>,
}
impl<C: Context> Participation<C> {
#[allow(clippy::arithmetic_side_effects)] pub(crate) fn new(highway: &Highway<C>) -> Self {
let now = Timestamp::now();
let state = highway.state();
let mut inactive_w = 0;
let mut faulty_w = 0;
let total_w = u128::from(state.total_weight().0);
let mut inactive_validators = Vec::new();
let mut faulty_validators = Vec::new();
for (idx, v_id) in highway.validators().enumerate_ids() {
if let Some(status) = Status::for_index(idx, state, now) {
match status {
Status::Equivocated | Status::EquivocatedInOtherEra => {
faulty_w += u128::from(state.weight(idx).0);
faulty_validators.push((idx, v_id.clone(), status));
}
Status::Inactive | Status::LastSeenSecondsAgo(_) => {
inactive_w += u128::from(state.weight(idx).0);
inactive_validators.push((idx, v_id.clone(), status));
}
}
}
}
inactive_validators.sort_by_key(|(idx, _, status)| (Reverse(*status), *idx));
faulty_validators.sort_by_key(|(idx, _, status)| (Reverse(*status), *idx));
Participation {
instance_id: *highway.instance_id(),
inactive_stake_percent: div_round(inactive_w * 100, total_w) as u8,
faulty_stake_percent: div_round(faulty_w * 100, total_w) as u8,
inactive_validators,
faulty_validators,
}
}
}