use std::{cmp::max, collections::BTreeMap, num::NonZeroU64};
use hotshot_types::{
traits::{
election::Membership,
node_implementation::NodeType,
signature_key::{SignatureKey, StakeTableEntryType},
},
PeerConfig,
};
use primitive_types::U256;
use utils::anytrace::Result;
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub struct StaticCommittee<T: NodeType> {
eligible_leaders: Vec<<T::SignatureKey as SignatureKey>::StakeTableEntry>,
stake_table: Vec<<T::SignatureKey as SignatureKey>::StakeTableEntry>,
da_stake_table: Vec<<T::SignatureKey as SignatureKey>::StakeTableEntry>,
indexed_stake_table:
BTreeMap<T::SignatureKey, <T::SignatureKey as SignatureKey>::StakeTableEntry>,
indexed_da_stake_table:
BTreeMap<T::SignatureKey, <T::SignatureKey as SignatureKey>::StakeTableEntry>,
}
impl<TYPES: NodeType> Membership<TYPES> for StaticCommittee<TYPES> {
type Error = utils::anytrace::Error;
fn new(
committee_members: Vec<PeerConfig<<TYPES as NodeType>::SignatureKey>>,
da_members: Vec<PeerConfig<<TYPES as NodeType>::SignatureKey>>,
) -> Self {
let eligible_leaders: Vec<<TYPES::SignatureKey as SignatureKey>::StakeTableEntry> =
committee_members
.iter()
.map(|member| member.stake_table_entry.clone())
.filter(|entry| entry.stake() > U256::zero())
.collect();
let members: Vec<<TYPES::SignatureKey as SignatureKey>::StakeTableEntry> =
committee_members
.iter()
.map(|member| member.stake_table_entry.clone())
.filter(|entry| entry.stake() > U256::zero())
.collect();
let da_members: Vec<<TYPES::SignatureKey as SignatureKey>::StakeTableEntry> = da_members
.iter()
.map(|member| member.stake_table_entry.clone())
.filter(|entry| entry.stake() > U256::zero())
.collect();
let indexed_stake_table: BTreeMap<
TYPES::SignatureKey,
<TYPES::SignatureKey as SignatureKey>::StakeTableEntry,
> = members
.iter()
.map(|entry| (TYPES::SignatureKey::public_key(entry), entry.clone()))
.collect();
let indexed_da_stake_table: BTreeMap<
TYPES::SignatureKey,
<TYPES::SignatureKey as SignatureKey>::StakeTableEntry,
> = da_members
.iter()
.map(|entry| (TYPES::SignatureKey::public_key(entry), entry.clone()))
.collect();
Self {
eligible_leaders,
stake_table: members,
da_stake_table: da_members,
indexed_stake_table,
indexed_da_stake_table,
}
}
fn stake_table(
&self,
_epoch: <TYPES as NodeType>::Epoch,
) -> Vec<<<TYPES as NodeType>::SignatureKey as SignatureKey>::StakeTableEntry> {
self.stake_table.clone()
}
fn da_stake_table(
&self,
_epoch: <TYPES as NodeType>::Epoch,
) -> Vec<<<TYPES as NodeType>::SignatureKey as SignatureKey>::StakeTableEntry> {
self.da_stake_table.clone()
}
fn committee_members(
&self,
_view_number: <TYPES as NodeType>::View,
_epoch: <TYPES as NodeType>::Epoch,
) -> std::collections::BTreeSet<<TYPES as NodeType>::SignatureKey> {
self.stake_table
.iter()
.map(TYPES::SignatureKey::public_key)
.collect()
}
fn da_committee_members(
&self,
_view_number: <TYPES as NodeType>::View,
_epoch: <TYPES as NodeType>::Epoch,
) -> std::collections::BTreeSet<<TYPES as NodeType>::SignatureKey> {
self.da_stake_table
.iter()
.map(TYPES::SignatureKey::public_key)
.collect()
}
fn committee_leaders(
&self,
_view_number: <TYPES as NodeType>::View,
_epoch: <TYPES as NodeType>::Epoch,
) -> std::collections::BTreeSet<<TYPES as NodeType>::SignatureKey> {
self.eligible_leaders
.iter()
.map(TYPES::SignatureKey::public_key)
.collect()
}
fn stake(
&self,
pub_key: &<TYPES as NodeType>::SignatureKey,
_epoch: <TYPES as NodeType>::Epoch,
) -> Option<<TYPES::SignatureKey as SignatureKey>::StakeTableEntry> {
self.indexed_stake_table.get(pub_key).cloned()
}
fn da_stake(
&self,
pub_key: &<TYPES as NodeType>::SignatureKey,
_epoch: <TYPES as NodeType>::Epoch,
) -> Option<<TYPES::SignatureKey as SignatureKey>::StakeTableEntry> {
self.indexed_da_stake_table.get(pub_key).cloned()
}
fn has_stake(
&self,
pub_key: &<TYPES as NodeType>::SignatureKey,
_epoch: <TYPES as NodeType>::Epoch,
) -> bool {
self.indexed_stake_table
.get(pub_key)
.is_some_and(|x| x.stake() > U256::zero())
}
fn has_da_stake(
&self,
pub_key: &<TYPES as NodeType>::SignatureKey,
_epoch: <TYPES as NodeType>::Epoch,
) -> bool {
self.indexed_da_stake_table
.get(pub_key)
.is_some_and(|x| x.stake() > U256::zero())
}
fn lookup_leader(
&self,
view_number: TYPES::View,
_epoch: <TYPES as NodeType>::Epoch,
) -> Result<TYPES::SignatureKey> {
#[allow(clippy::cast_possible_truncation)]
let index = *view_number as usize % self.eligible_leaders.len();
let res = self.eligible_leaders[index].clone();
Ok(TYPES::SignatureKey::public_key(&res))
}
fn total_nodes(&self, _epoch: <TYPES as NodeType>::Epoch) -> usize {
self.stake_table.len()
}
fn da_total_nodes(&self, _epoch: <TYPES as NodeType>::Epoch) -> usize {
self.da_stake_table.len()
}
fn success_threshold(&self, _epoch: TYPES::Epoch) -> NonZeroU64 {
NonZeroU64::new(((self.stake_table.len() as u64 * 2) / 3) + 1).unwrap()
}
fn da_success_threshold(&self, _epoch: TYPES::Epoch) -> NonZeroU64 {
NonZeroU64::new(((self.da_stake_table.len() as u64 * 2) / 3) + 1).unwrap()
}
fn failure_threshold(&self, _epoch: TYPES::Epoch) -> NonZeroU64 {
NonZeroU64::new(((self.stake_table.len() as u64) / 3) + 1).unwrap()
}
fn upgrade_threshold(&self, _epoch: TYPES::Epoch) -> NonZeroU64 {
let len = self.stake_table.len();
NonZeroU64::new(max((len as u64 * 9) / 10, ((len as u64 * 2) / 3) + 1)).unwrap()
}
}