sui_core/
scoring_decision.rsuse std::{collections::HashMap, sync::Arc};
use arc_swap::ArcSwap;
use consensus_config::Committee as ConsensusCommittee;
use sui_types::{
base_types::AuthorityName, committee::Committee, messages_consensus::AuthorityIndex,
};
use tracing::debug;
use crate::authority::AuthorityMetrics;
pub(crate) fn update_low_scoring_authorities(
low_scoring_authorities: Arc<ArcSwap<HashMap<AuthorityName, u64>>>,
sui_committee: &Committee,
consensus_committee: &ConsensusCommittee,
reputation_score_sorted_desc: Option<Vec<(AuthorityIndex, u64)>>,
metrics: &Arc<AuthorityMetrics>,
consensus_bad_nodes_stake_threshold: u64,
) {
assert!((0..=33).contains(&consensus_bad_nodes_stake_threshold), "The bad_nodes_stake_threshold should be in range [0 - 33], out of bounds parameter detected {}", consensus_bad_nodes_stake_threshold);
let Some(reputation_scores) = reputation_score_sorted_desc else {
return;
};
let scores_per_authority_order_asc: Vec<_> = reputation_scores
.into_iter()
.rev() .collect();
let mut final_low_scoring_map = HashMap::new();
let mut total_stake = 0;
for (index, score) in scores_per_authority_order_asc {
let authority_name = sui_committee.authority_by_index(index).unwrap();
let authority_index = consensus_committee
.to_authority_index(index as usize)
.unwrap();
let consensus_authority = consensus_committee.authority(authority_index);
let hostname = &consensus_authority.hostname;
let stake = consensus_authority.stake;
total_stake += stake;
let included = if total_stake
<= consensus_bad_nodes_stake_threshold * consensus_committee.total_stake() / 100
{
final_low_scoring_map.insert(*authority_name, score);
true
} else {
false
};
if !hostname.is_empty() {
debug!(
"authority {} has score {}, is low scoring: {}",
hostname, score, included
);
metrics
.consensus_handler_scores
.with_label_values(&[hostname])
.set(score as i64);
}
}
metrics
.consensus_handler_num_low_scoring_authorities
.set(final_low_scoring_map.len() as i64);
low_scoring_authorities.swap(Arc::new(final_low_scoring_map));
}
#[cfg(test)]
mod tests {
#![allow(clippy::mutable_key_type)]
use std::{collections::HashMap, sync::Arc};
use arc_swap::ArcSwap;
use consensus_config::{local_committee_and_keys, Committee as ConsensusCommittee};
use prometheus::Registry;
use sui_types::{committee::Committee, crypto::AuthorityPublicKeyBytes};
use crate::{authority::AuthorityMetrics, scoring_decision::update_low_scoring_authorities};
#[test]
#[cfg_attr(msim, ignore)]
pub fn test_update_low_scoring_authorities() {
let (sui_committee, consensus_committee) = generate_committees(8);
let low_scoring = Arc::new(ArcSwap::from_pointee(HashMap::new()));
let metrics = Arc::new(AuthorityMetrics::new(&Registry::new()));
let authorities_by_score_desc = vec![
(1, 390_u64),
(0, 350_u64),
(6, 340_u64),
(7, 310_u64),
(5, 300_u64),
(3, 50_u64),
(2, 50_u64),
(4, 0_u64), ];
let consensus_bad_nodes_stake_threshold = 33; update_low_scoring_authorities(
low_scoring.clone(),
&sui_committee,
&consensus_committee,
Some(authorities_by_score_desc.clone()),
&metrics,
consensus_bad_nodes_stake_threshold,
);
assert_eq!(low_scoring.load().len(), 2);
assert_eq!(
*low_scoring
.load()
.get(sui_committee.authority_by_index(2).unwrap())
.unwrap(),
50
);
assert_eq!(
*low_scoring
.load()
.get(sui_committee.authority_by_index(4).unwrap())
.unwrap(),
0
);
let consensus_bad_nodes_stake_threshold = 20; update_low_scoring_authorities(
low_scoring.clone(),
&sui_committee,
&consensus_committee,
Some(authorities_by_score_desc.clone()),
&metrics,
consensus_bad_nodes_stake_threshold,
);
assert_eq!(low_scoring.load().len(), 1);
assert_eq!(
*low_scoring
.load()
.get(sui_committee.authority_by_index(4).unwrap())
.unwrap(),
0
);
}
fn generate_committees(committee_size: usize) -> (Committee, ConsensusCommittee) {
let (consensus_committee, _) = local_committee_and_keys(0, vec![1; committee_size]);
let public_keys = consensus_committee
.authorities()
.map(|(_i, authority)| authority.authority_key.inner())
.collect::<Vec<_>>();
let sui_authorities = public_keys
.iter()
.map(|key| (AuthorityPublicKeyBytes::from(*key), 1))
.collect::<Vec<_>>();
let sui_committee = Committee::new_for_testing_with_normalized_voting_power(
0,
sui_authorities.iter().cloned().collect(),
);
(sui_committee, consensus_committee)
}
}