starfish_config/
committee.rs1use std::{
6 fmt::{Display, Formatter},
7 ops::{Index, IndexMut},
8};
9
10use iota_network_stack::Multiaddr;
11use serde::{Deserialize, Serialize};
12
13use crate::{AuthorityPublicKey, NetworkPublicKey, ProtocolPublicKey};
14
15pub type Epoch = u64;
17
18pub type Stake = u64;
22
23#[derive(Clone, Debug, Serialize, Deserialize)]
27pub struct Committee {
28 epoch: Epoch,
30 total_stake: Stake,
32 quorum_threshold: Stake,
34 validity_threshold: Stake,
36 authorities: Vec<Authority>,
39 info_length: usize,
43}
44
45impl Committee {
46 pub fn new(epoch: Epoch, authorities: Vec<Authority>) -> Self {
47 assert!(!authorities.is_empty(), "Committee cannot be empty!");
48 assert!(
49 authorities.len() < u8::MAX as usize,
50 "Too many authorities ({})!",
51 authorities.len()
52 );
53
54 let total_stake = authorities.iter().map(|a| a.stake).sum::<u64>();
55 assert_ne!(total_stake, 0, "Total stake cannot be zero!");
56 let quorum_threshold = 2 * total_stake / 3 + 1;
57 let validity_threshold = total_stake.div_ceil(3);
58 let committee_size = authorities.len();
59 let f = (committee_size - 1) / 3;
62 let info_length = committee_size - 2 * f;
63 Self {
64 epoch,
65 total_stake,
66 quorum_threshold,
67 validity_threshold,
68 authorities,
69 info_length,
70 }
71 }
72
73 pub fn epoch(&self) -> Epoch {
77 self.epoch
78 }
79
80 pub fn total_stake(&self) -> Stake {
81 self.total_stake
82 }
83
84 pub fn quorum_threshold(&self) -> Stake {
85 self.quorum_threshold
86 }
87
88 pub fn validity_threshold(&self) -> Stake {
89 self.validity_threshold
90 }
91
92 pub fn info_length(&self) -> usize {
93 self.info_length
94 }
95
96 pub fn parity_length(&self) -> usize {
97 self.size() - self.info_length()
98 }
99
100 pub fn stake(&self, authority_index: AuthorityIndex) -> Stake {
101 self.authorities[authority_index].stake
102 }
103
104 pub fn authority(&self, authority_index: AuthorityIndex) -> &Authority {
105 &self.authorities[authority_index]
106 }
107
108 pub fn authorities(&self) -> impl Iterator<Item = (AuthorityIndex, &Authority)> {
109 self.authorities
110 .iter()
111 .enumerate()
112 .map(|(i, a)| (AuthorityIndex(i as u8), a))
113 }
114
115 pub fn reached_quorum(&self, stake: Stake) -> bool {
120 stake >= self.quorum_threshold()
121 }
122
123 pub fn reached_validity(&self, stake: Stake) -> bool {
125 stake >= self.validity_threshold()
126 }
127
128 pub fn to_authority_index(&self, index: usize) -> Option<AuthorityIndex> {
131 if index < self.authorities.len() {
132 Some(AuthorityIndex(index as u8))
133 } else {
134 None
135 }
136 }
137
138 pub fn is_valid_index(&self, index: AuthorityIndex) -> bool {
140 index.value() < self.size()
141 }
142
143 pub fn size(&self) -> usize {
145 self.authorities.len()
146 }
147}
148
149#[derive(Clone, Debug, Serialize, Deserialize)]
154pub struct Authority {
155 pub stake: Stake,
157 pub address: Multiaddr,
159 pub hostname: String,
161 pub authority_key: AuthorityPublicKey,
164 pub protocol_key: ProtocolPublicKey,
167 pub network_key: NetworkPublicKey,
170}
171
172#[derive(
180 Eq, PartialEq, Ord, PartialOrd, Clone, Copy, Debug, Default, Hash, Serialize, Deserialize,
181)]
182pub struct AuthorityIndex(u8);
183
184impl AuthorityIndex {
185 pub const ZERO: Self = Self(0);
187
188 pub const MIN: Self = Self::ZERO;
190 pub const MAX: Self = Self(u8::MAX);
191
192 pub fn value(&self) -> usize {
193 self.0 as usize
194 }
195}
196
197impl From<u8> for AuthorityIndex {
198 fn from(value: u8) -> Self {
199 Self(value)
200 }
201}
202
203impl AuthorityIndex {
204 pub fn new_for_test(index: u8) -> Self {
205 Self(index)
206 }
207}
208
209impl Display for AuthorityIndex {
210 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
211 write!(f, "[{}]", self.value())
212 }
213}
214
215impl<T, const N: usize> Index<AuthorityIndex> for [T; N] {
216 type Output = T;
217
218 fn index(&self, index: AuthorityIndex) -> &Self::Output {
219 self.get(index.value()).unwrap()
220 }
221}
222
223impl<T> Index<AuthorityIndex> for Vec<T> {
224 type Output = T;
225
226 fn index(&self, index: AuthorityIndex) -> &Self::Output {
227 self.get(index.value()).unwrap()
228 }
229}
230
231impl<T, const N: usize> IndexMut<AuthorityIndex> for [T; N] {
232 fn index_mut(&mut self, index: AuthorityIndex) -> &mut Self::Output {
233 self.get_mut(index.value()).unwrap()
234 }
235}
236
237impl<T> IndexMut<AuthorityIndex> for Vec<T> {
238 fn index_mut(&mut self, index: AuthorityIndex) -> &mut Self::Output {
239 self.get_mut(index.value()).unwrap()
240 }
241}
242
243#[cfg(test)]
244mod tests {
245 use super::*;
246 use crate::local_committee_and_keys;
247
248 #[test]
249 fn committee_basic() {
250 let epoch = 100;
252 let num_of_authorities = 9;
253 let authority_stakes = (1..=9).map(|s| s as Stake).collect();
254 let (committee, _) = local_committee_and_keys(epoch, authority_stakes);
255
256 assert_eq!(committee.size(), num_of_authorities);
258 for (i, authority) in committee.authorities() {
259 assert_eq!((i.value() + 1) as Stake, authority.stake);
260 }
261
262 assert_eq!(committee.total_stake(), 45);
264 assert_eq!(committee.quorum_threshold(), 31);
265 assert_eq!(committee.validity_threshold(), 15);
266 }
267}