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 {
51 assert!(!authorities.is_empty(), "Committee cannot be empty!");
52 assert!(
53 authorities.len() < u8::MAX as usize,
54 "Too many authorities ({})!",
55 authorities.len()
56 );
57
58 for authority in &authorities {
59 assert!(
60 authority.stake > 0,
61 "Authority {} cannot have zero stake!",
62 authority.hostname
63 );
64 }
65
66 let total_stake = authorities
67 .iter()
68 .map(|a| a.stake)
69 .try_fold(0u64, u64::checked_add)
70 .expect("Total stake must not overflow u64!");
71 let quorum_threshold = (2 * total_stake as u128 / 3 + 1) as u64;
73 let validity_threshold = total_stake.div_ceil(3);
74 let committee_size = authorities.len();
75 let f = (committee_size - 1) / 3;
78 let info_length = committee_size - 2 * f;
79 Self {
80 epoch,
81 total_stake,
82 quorum_threshold,
83 validity_threshold,
84 authorities,
85 info_length,
86 }
87 }
88
89 pub fn epoch(&self) -> Epoch {
93 self.epoch
94 }
95
96 pub fn total_stake(&self) -> Stake {
97 self.total_stake
98 }
99
100 pub fn quorum_threshold(&self) -> Stake {
101 self.quorum_threshold
102 }
103
104 pub fn validity_threshold(&self) -> Stake {
105 self.validity_threshold
106 }
107
108 pub fn info_length(&self) -> usize {
109 self.info_length
110 }
111
112 pub fn parity_length(&self) -> usize {
113 self.size() - self.info_length()
114 }
115
116 pub fn stake(&self, authority_index: AuthorityIndex) -> Stake {
117 self.authorities[authority_index].stake
118 }
119
120 pub fn authority(&self, authority_index: AuthorityIndex) -> &Authority {
121 &self.authorities[authority_index]
122 }
123
124 pub fn authorities(&self) -> impl Iterator<Item = (AuthorityIndex, &Authority)> {
125 self.authorities
126 .iter()
127 .enumerate()
128 .map(|(i, a)| (AuthorityIndex(i as u8), a))
129 }
130
131 pub fn reached_quorum(&self, stake: Stake) -> bool {
136 stake >= self.quorum_threshold()
137 }
138
139 pub fn reached_validity(&self, stake: Stake) -> bool {
141 stake >= self.validity_threshold()
142 }
143
144 pub fn to_authority_index(&self, index: usize) -> Option<AuthorityIndex> {
147 if index < self.authorities.len() {
148 Some(AuthorityIndex(index as u8))
149 } else {
150 None
151 }
152 }
153
154 pub fn is_valid_index(&self, index: AuthorityIndex) -> bool {
156 index.value() < self.size()
157 }
158
159 pub fn size(&self) -> usize {
161 self.authorities.len()
162 }
163}
164
165#[derive(Clone, Debug, Serialize, Deserialize)]
170pub struct Authority {
171 pub stake: Stake,
173 pub address: Multiaddr,
175 pub hostname: String,
177 pub authority_key: AuthorityPublicKey,
180 pub protocol_key: ProtocolPublicKey,
183 pub network_key: NetworkPublicKey,
186}
187
188#[derive(
196 Eq, PartialEq, Ord, PartialOrd, Clone, Copy, Debug, Default, Hash, Serialize, Deserialize,
197)]
198pub struct AuthorityIndex(u8);
199
200impl AuthorityIndex {
201 pub const ZERO: Self = Self(0);
203
204 pub const MIN: Self = Self::ZERO;
206 pub const MAX: Self = Self(u8::MAX);
207
208 pub fn value(&self) -> usize {
209 self.0 as usize
210 }
211}
212
213impl From<u8> for AuthorityIndex {
214 fn from(value: u8) -> Self {
215 Self(value)
216 }
217}
218
219impl AuthorityIndex {
220 pub fn new_for_test(index: u8) -> Self {
221 Self(index)
222 }
223}
224
225impl Display for AuthorityIndex {
226 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
227 write!(f, "[{}]", self.value())
228 }
229}
230
231impl<T, const N: usize> Index<AuthorityIndex> for [T; N] {
232 type Output = T;
233
234 fn index(&self, index: AuthorityIndex) -> &Self::Output {
235 self.get(index.value()).unwrap()
236 }
237}
238
239impl<T> Index<AuthorityIndex> for Vec<T> {
240 type Output = T;
241
242 fn index(&self, index: AuthorityIndex) -> &Self::Output {
243 self.get(index.value()).unwrap()
244 }
245}
246
247impl<T, const N: usize> IndexMut<AuthorityIndex> for [T; N] {
248 fn index_mut(&mut self, index: AuthorityIndex) -> &mut Self::Output {
249 self.get_mut(index.value()).unwrap()
250 }
251}
252
253impl<T> IndexMut<AuthorityIndex> for Vec<T> {
254 fn index_mut(&mut self, index: AuthorityIndex) -> &mut Self::Output {
255 self.get_mut(index.value()).unwrap()
256 }
257}
258
259#[cfg(test)]
260mod tests {
261 use super::*;
262 use crate::local_committee_and_keys;
263
264 #[test]
265 fn committee_basic() {
266 let epoch = 100;
268 let num_of_authorities = 9;
269 let authority_stakes = (1..=9).map(|s| s as Stake).collect();
270 let (committee, _) = local_committee_and_keys(epoch, authority_stakes);
271
272 assert_eq!(committee.size(), num_of_authorities);
274 for (i, authority) in committee.authorities() {
275 assert_eq!((i.value() + 1) as Stake, authority.stake);
276 }
277
278 assert_eq!(committee.total_stake(), 45);
280 assert_eq!(committee.quorum_threshold(), 31);
281 assert_eq!(committee.validity_threshold(), 15);
282 }
283}