starfish_config/
committee.rs1use std::{
6 fmt::{Display, Formatter},
7 ops::{Index, IndexMut},
8};
9
10use iota_network_stack::Multiaddr;
11use iota_sdk_types::ValidatorCommittee;
12use serde::{Deserialize, Serialize};
13
14use crate::{AuthorityPublicKey, NetworkPublicKey, ProtocolPublicKey};
15
16pub type Epoch = u64;
18
19pub type Stake = u64;
23
24pub const MAX_COMMITTEE_SIZE: usize = u8::MAX as usize;
27
28#[derive(Clone, Debug, Serialize, Deserialize)]
32pub struct Committee {
33 epoch: Epoch,
35 total_stake: Stake,
37 quorum_threshold: Stake,
39 validity_threshold: Stake,
41 authorities: Vec<Authority>,
44 info_length: usize,
48}
49
50impl Committee {
51 pub fn new(epoch: Epoch, authorities: Vec<Authority>) -> Self {
56 assert!(!authorities.is_empty(), "Committee cannot be empty!");
57 assert!(
58 authorities.len() <= MAX_COMMITTEE_SIZE,
59 "Too many authorities ({})!",
60 authorities.len()
61 );
62
63 for authority in &authorities {
64 assert!(
65 authority.stake > 0,
66 "Authority {} cannot have zero stake!",
67 authority.hostname
68 );
69 }
70
71 let total_stake = authorities
72 .iter()
73 .map(|a| a.stake)
74 .try_fold(0u64, u64::checked_add)
75 .expect("Total stake must not overflow u64!");
76 let quorum_threshold = ValidatorCommittee::quorum_threshold(total_stake);
77 let validity_threshold = total_stake.div_ceil(3);
78 let committee_size = authorities.len();
79 let f = (committee_size - 1) / 3;
82 let info_length = committee_size - 2 * f;
83 Self {
84 epoch,
85 total_stake,
86 quorum_threshold,
87 validity_threshold,
88 authorities,
89 info_length,
90 }
91 }
92
93 pub fn epoch(&self) -> Epoch {
97 self.epoch
98 }
99
100 pub fn total_stake(&self) -> Stake {
101 self.total_stake
102 }
103
104 pub fn quorum_threshold(&self) -> Stake {
105 self.quorum_threshold
106 }
107
108 pub fn validity_threshold(&self) -> Stake {
109 self.validity_threshold
110 }
111
112 pub fn info_length(&self) -> usize {
113 self.info_length
114 }
115
116 pub fn parity_length(&self) -> usize {
117 self.size() - self.info_length()
118 }
119
120 pub fn stake(&self, authority_index: AuthorityIndex) -> Stake {
121 self.authorities[authority_index].stake
122 }
123
124 pub fn authority(&self, authority_index: AuthorityIndex) -> &Authority {
125 &self.authorities[authority_index]
126 }
127
128 pub fn authorities(&self) -> impl Iterator<Item = (AuthorityIndex, &Authority)> {
129 self.authorities
130 .iter()
131 .enumerate()
132 .map(|(i, a)| (AuthorityIndex(i as u8), a))
133 }
134
135 pub fn reached_quorum(&self, stake: Stake) -> bool {
140 stake >= self.quorum_threshold()
141 }
142
143 pub fn reached_validity(&self, stake: Stake) -> bool {
145 stake >= self.validity_threshold()
146 }
147
148 pub fn to_authority_index(&self, index: usize) -> Option<AuthorityIndex> {
151 if index < self.authorities.len() {
152 Some(AuthorityIndex(index as u8))
153 } else {
154 None
155 }
156 }
157
158 pub fn is_valid_index(&self, index: AuthorityIndex) -> bool {
160 index.value() < self.size()
161 }
162
163 pub fn size(&self) -> usize {
165 self.authorities.len()
166 }
167}
168
169#[derive(Clone, Debug, Serialize, Deserialize)]
174pub struct Authority {
175 pub stake: Stake,
177 pub address: Multiaddr,
179 pub hostname: String,
181 pub authority_key: AuthorityPublicKey,
184 pub protocol_key: ProtocolPublicKey,
187 pub network_key: NetworkPublicKey,
190}
191
192#[derive(
200 Eq, PartialEq, Ord, PartialOrd, Clone, Copy, Debug, Default, Hash, Serialize, Deserialize,
201)]
202pub struct AuthorityIndex(u8);
203
204impl AuthorityIndex {
205 pub const ZERO: Self = Self(0);
207
208 pub const MIN: Self = Self::ZERO;
210 pub const MAX: Self = Self(u8::MAX);
211
212 pub const fn value(&self) -> usize {
213 self.0 as usize
214 }
215}
216
217impl From<u8> for AuthorityIndex {
218 fn from(value: u8) -> Self {
219 Self(value)
220 }
221}
222
223impl AuthorityIndex {
224 pub fn new_for_test(index: u8) -> Self {
225 Self(index)
226 }
227}
228
229impl Display for AuthorityIndex {
230 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
231 write!(f, "[{}]", self.value())
232 }
233}
234
235impl<T, const N: usize> Index<AuthorityIndex> for [T; N] {
236 type Output = T;
237
238 fn index(&self, index: AuthorityIndex) -> &Self::Output {
239 self.get(index.value()).unwrap()
240 }
241}
242
243impl<T> Index<AuthorityIndex> for Vec<T> {
244 type Output = T;
245
246 fn index(&self, index: AuthorityIndex) -> &Self::Output {
247 self.get(index.value()).unwrap()
248 }
249}
250
251impl<T, const N: usize> IndexMut<AuthorityIndex> for [T; N] {
252 fn index_mut(&mut self, index: AuthorityIndex) -> &mut Self::Output {
253 self.get_mut(index.value()).unwrap()
254 }
255}
256
257impl<T> IndexMut<AuthorityIndex> for Vec<T> {
258 fn index_mut(&mut self, index: AuthorityIndex) -> &mut Self::Output {
259 self.get_mut(index.value()).unwrap()
260 }
261}
262
263#[cfg(test)]
264mod tests {
265 use super::*;
266 use crate::local_committee_and_keys;
267
268 #[test]
269 fn committee_basic() {
270 let epoch = 100;
272 let num_of_authorities = 9;
273 let authority_stakes = (1..=9).map(|s| s as Stake).collect();
274 let (committee, _) = local_committee_and_keys(epoch, authority_stakes);
275
276 assert_eq!(committee.size(), num_of_authorities);
278 for (i, authority) in committee.authorities() {
279 assert_eq!((i.value() + 1) as Stake, authority.stake);
280 }
281
282 assert_eq!(committee.total_stake(), 45);
284 assert_eq!(committee.quorum_threshold(), 31);
285 assert_eq!(committee.validity_threshold(), 15);
286 }
287}