use std::collections::{BTreeMap, HashMap};
use std::{fmt, mem};
use node_data::bls::{PublicKey, PublicKeyBytes};
use super::cluster::Cluster;
use crate::config::{majority, supermajority};
use crate::user::provisioners::Provisioners;
use crate::user::sortition;
#[derive(Default, Debug, Clone)]
pub struct Committee {
members: BTreeMap<PublicKey, usize>,
super_majority: usize,
majority: usize,
excluded: Vec<PublicKeyBytes>,
}
impl Committee {
pub fn iter(&self) -> impl Iterator<Item = &PublicKey> {
self.members.keys()
}
}
impl Committee {
pub fn new(provisioners: &Provisioners, cfg: &sortition::Config) -> Self {
let extracted = provisioners.create_committee(cfg);
let committee_credits = cfg.committee_credits();
let majority = majority(committee_credits);
let super_majority = supermajority(committee_credits);
let mut committee = Self {
members: BTreeMap::new(),
super_majority,
majority,
excluded: cfg.exclusion().clone(),
};
for member_key in extracted {
*committee.members.entry(member_key).or_insert(0) += 1;
}
committee
}
pub fn excluded(&self) -> &Vec<PublicKeyBytes> {
&self.excluded
}
pub fn is_member(&self, pubkey_bls: &PublicKey) -> bool {
self.members.contains_key(pubkey_bls)
}
pub fn votes_for(&self, pubkey_bls: &PublicKey) -> Option<usize> {
self.members.get(pubkey_bls).copied()
}
pub fn members(&self) -> &BTreeMap<PublicKey, usize> {
&self.members
}
pub fn get_occurrences(&self) -> Vec<usize> {
self.members.values().copied().collect()
}
pub fn size(&self) -> usize {
self.members.len()
}
pub fn super_majority_quorum(&self) -> usize {
self.super_majority
}
pub fn majority_quorum(&self) -> usize {
self.majority
}
pub fn bits(&self, voters: &Cluster<PublicKey>) -> u64 {
let mut bits: u64 = 0;
debug_assert!(self.members.len() <= mem::size_of_val(&bits) * 8);
for (pos, (member_pk, _)) in self.members.iter().enumerate() {
if voters.contains_key(member_pk) {
bits |= 1 << pos; }
}
bits
}
pub fn intersect(&self, bitset: u64) -> Cluster<PublicKey> {
if bitset == 0 {
return Cluster::<PublicKey>::new();
}
let mut a = Cluster::new();
for (pos, (member_pk, weight)) in self.members.iter().enumerate() {
if ((bitset >> pos) & 1) != 0 {
a.add(member_pk, *weight);
}
}
a
}
pub fn total_occurrences(&self, voters: &Cluster<PublicKey>) -> usize {
voters
.iter()
.flat_map(|(voter, _)| self.votes_for(voter))
.sum()
}
}
impl fmt::Display for &Committee {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
for (pos, (member_pk, weight)) in self.members.iter().enumerate() {
write!(f, " [{}]=pk:{} w:{},", pos, member_pk.to_bs58(), weight)?;
}
Ok(())
}
}
#[derive(Clone)]
pub struct CommitteeSet<'p> {
committees: HashMap<sortition::Config, Committee>,
provisioners: &'p Provisioners,
}
impl<'p> CommitteeSet<'p> {
pub fn new(provisioners: &'p Provisioners) -> Self {
CommitteeSet {
provisioners,
committees: HashMap::new(),
}
}
pub fn get_or_create(&mut self, cfg: &sortition::Config) -> &Committee {
self.committees
.entry(cfg.clone())
.or_insert_with_key(|config| {
Committee::new(self.provisioners, config)
})
}
pub fn get(&self, cfg: &sortition::Config) -> Option<&Committee> {
self.committees.get(cfg)
}
pub fn provisioners(&self) -> &Provisioners {
self.provisioners
}
}