consensus_config/
committee.rs1use std::{
5 fmt::{Display, Formatter},
6 ops::{Index, IndexMut},
7};
8
9use mysten_network::Multiaddr;
10use serde::{Deserialize, Serialize};
11
12use crate::{AuthorityPublicKey, NetworkPublicKey, ProtocolPublicKey};
13
14pub type Epoch = u64;
16
17pub type Stake = u64;
21
22#[derive(Clone, Debug, Serialize, Deserialize)]
25pub struct Committee {
26 epoch: Epoch,
28 total_stake: Stake,
30 quorum_threshold: Stake,
32 validity_threshold: Stake,
34 authorities: Vec<Authority>,
36}
37
38impl Committee {
39 pub fn new(epoch: Epoch, authorities: Vec<Authority>) -> Self {
40 assert!(!authorities.is_empty(), "Committee cannot be empty!");
41 assert!(
42 authorities.len() < u32::MAX as usize,
43 "Too many authorities ({})!",
44 authorities.len()
45 );
46
47 let total_stake: Stake = authorities.iter().map(|a| a.stake).sum();
48 assert_ne!(total_stake, 0, "Total stake cannot be zero!");
49
50 let fault_tolerance = (total_stake - 1) / 3;
52 let quorum_threshold = total_stake - fault_tolerance;
53 let validity_threshold = fault_tolerance + 1;
54 assert!(
55 2 * quorum_threshold - fault_tolerance > total_stake,
56 "Quorum must intersect under maxim equivocations! Quorum: {quorum_threshold}, Fault tolerance: {fault_tolerance}, Total: {total_stake}"
57 );
58
59 Self {
60 epoch,
61 total_stake,
62 quorum_threshold,
63 validity_threshold,
64 authorities,
65 }
66 }
67
68 pub fn epoch(&self) -> Epoch {
72 self.epoch
73 }
74
75 pub fn total_stake(&self) -> Stake {
76 self.total_stake
77 }
78
79 pub fn quorum_threshold(&self) -> Stake {
80 self.quorum_threshold
81 }
82
83 pub fn validity_threshold(&self) -> Stake {
84 self.validity_threshold
85 }
86
87 pub fn stake(&self, authority_index: AuthorityIndex) -> Stake {
88 self.authorities[authority_index].stake
89 }
90
91 pub fn authority(&self, authority_index: AuthorityIndex) -> &Authority {
92 &self.authorities[authority_index]
93 }
94
95 pub fn authorities(&self) -> impl Iterator<Item = (AuthorityIndex, &Authority)> {
96 self.authorities
97 .iter()
98 .enumerate()
99 .map(|(i, a)| (AuthorityIndex(i as u32), a))
100 }
101
102 pub fn reached_quorum(&self, stake: Stake) -> bool {
107 stake >= self.quorum_threshold()
108 }
109
110 pub fn reached_validity(&self, stake: Stake) -> bool {
112 stake >= self.validity_threshold()
113 }
114
115 pub fn to_authority_index(&self, index: usize) -> Option<AuthorityIndex> {
118 if index < self.authorities.len() {
119 Some(AuthorityIndex(index as u32))
120 } else {
121 None
122 }
123 }
124
125 pub fn is_valid_index(&self, index: AuthorityIndex) -> bool {
127 index.value() < self.size()
128 }
129
130 pub fn size(&self) -> usize {
132 self.authorities.len()
133 }
134}
135
136#[derive(Clone, Debug, Serialize, Deserialize)]
141pub struct Authority {
142 pub stake: Stake,
144 pub address: Multiaddr,
146 pub hostname: String,
148 pub authority_key: AuthorityPublicKey,
150 pub protocol_key: ProtocolPublicKey,
152 pub network_key: NetworkPublicKey,
154}
155
156#[derive(
163 Eq, PartialEq, Ord, PartialOrd, Clone, Copy, Debug, Default, Hash, Serialize, Deserialize,
164)]
165pub struct AuthorityIndex(u32);
166
167impl AuthorityIndex {
168 pub const ZERO: Self = Self(0);
170
171 pub const MIN: Self = Self::ZERO;
173 pub const MAX: Self = Self(u32::MAX);
174
175 pub fn value(&self) -> usize {
176 self.0 as usize
177 }
178}
179
180impl AuthorityIndex {
181 pub fn new_for_test(index: u32) -> Self {
182 Self(index)
183 }
184}
185
186impl Display for AuthorityIndex {
187 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
188 write!(f, "[{}]", self.value())
189 }
190}
191
192impl<T, const N: usize> Index<AuthorityIndex> for [T; N] {
193 type Output = T;
194
195 fn index(&self, index: AuthorityIndex) -> &Self::Output {
196 self.get(index.value()).unwrap()
197 }
198}
199
200impl<T> Index<AuthorityIndex> for Vec<T> {
201 type Output = T;
202
203 fn index(&self, index: AuthorityIndex) -> &Self::Output {
204 self.get(index.value()).unwrap()
205 }
206}
207
208impl<T, const N: usize> IndexMut<AuthorityIndex> for [T; N] {
209 fn index_mut(&mut self, index: AuthorityIndex) -> &mut Self::Output {
210 self.get_mut(index.value()).unwrap()
211 }
212}
213
214impl<T> IndexMut<AuthorityIndex> for Vec<T> {
215 fn index_mut(&mut self, index: AuthorityIndex) -> &mut Self::Output {
216 self.get_mut(index.value()).unwrap()
217 }
218}
219
220#[cfg(test)]
221mod tests {
222 use super::*;
223 use crate::local_committee_and_keys;
224
225 #[test]
226 fn committee_basic() {
227 let epoch = 100;
229 let num_of_authorities = 10;
230 let authority_stakes = (1..=num_of_authorities).map(|s| s as Stake).collect();
231 let (committee, _) = local_committee_and_keys(epoch, authority_stakes);
232
233 assert_eq!(committee.size(), num_of_authorities);
235 for (i, authority) in committee.authorities() {
236 assert_eq!((i.value() + 1) as Stake, authority.stake);
237 }
238
239 assert_eq!(committee.total_stake(), 55);
241 assert_eq!(committee.quorum_threshold(), 37);
242 assert_eq!(committee.validity_threshold(), 19);
243 }
244
245 #[test]
246 fn committee_different_sizes() {
247 let epoch = 100;
248
249 {
250 let num_of_authorities = 11;
251 let authority_stakes = (1..=num_of_authorities).map(|_| 1 as Stake).collect();
252 let (committee, _) = local_committee_and_keys(epoch, authority_stakes);
253
254 assert_eq!(committee.total_stake(), 11);
256 assert_eq!(committee.quorum_threshold(), 8);
257 assert_eq!(committee.validity_threshold(), 4);
258 }
259
260 {
261 let num_of_authorities = 12;
262 let authority_stakes = (1..=num_of_authorities).map(|_| 10 as Stake).collect();
263 let (committee, _) = local_committee_and_keys(epoch, authority_stakes);
264
265 assert_eq!(committee.total_stake(), 120);
267 assert_eq!(committee.quorum_threshold(), 81);
268 assert_eq!(committee.validity_threshold(), 40);
269 }
270 }
271}