overlord/utils/
auth_manage.rs

1use std::collections::HashMap;
2
3use bit_vec::BitVec;
4use derive_more::Display;
5use prime_tools::get_primes_less_than_x;
6
7use crate::error::ConsensusError;
8use crate::types::{Address, Node};
9use crate::utils::rand_proposer::get_random_proposer_index;
10use crate::ConsensusResult;
11
12/// Authority manage is an extensional data structure of authority list which means
13/// `Vec<Node>`. It transforms the information in `Node` struct into a more suitable data structure
14/// according to its usage scene. The vote weight need look up by address frequently, therefore,
15/// address with vote weight saved in a `HashMap`.
16#[derive(Clone, Debug, Display, PartialEq, Eq)]
17#[display(fmt = "Authority List {:?}", address)]
18pub struct AuthorityManage {
19    address: Vec<Address>,
20    propose_weights: Vec<u64>,
21    vote_weight_map: HashMap<Address, u32>,
22    propose_weight_sum: u64,
23    vote_weight_sum: u64,
24}
25
26impl AuthorityManage {
27    /// Create a new height authority manage.
28    pub fn new() -> Self {
29        AuthorityManage {
30            address: Vec::new(),
31            propose_weights: Vec::new(),
32            vote_weight_map: HashMap::new(),
33            propose_weight_sum: 0u64,
34            vote_weight_sum: 0u64,
35        }
36    }
37
38    /// Update the height authority manage by a new authority list.
39    pub fn update(&mut self, authority_list: &mut [Node]) {
40        self.flush();
41        authority_list.sort();
42
43        for node in authority_list.iter_mut() {
44            let propose_weight = u64::from(node.propose_weight);
45            let vote_weight = node.vote_weight;
46
47            self.address.push(node.address.clone());
48            self.propose_weights.push(propose_weight);
49            self.vote_weight_map
50                .insert(node.address.clone(), vote_weight);
51            self.propose_weight_sum += propose_weight;
52            self.vote_weight_sum += u64::from(vote_weight);
53        }
54    }
55
56    /// Get a vote weight of the node.
57    pub fn get_vote_weight(&self, addr: &Address) -> ConsensusResult<&u32> {
58        self.vote_weight_map
59            .get(addr)
60            .ok_or(ConsensusError::InvalidAddress)
61    }
62
63    /// Get the proposer address by a given seed.
64    pub fn get_proposer(&self, height: u64, round: u64) -> ConsensusResult<Address> {
65        let index = if cfg!(feature = "random_leader") {
66            get_random_proposer_index(
67                height + round,
68                &self.propose_weights,
69                self.propose_weight_sum,
70            )
71        } else {
72            rotation_leader_index(height, round, self.address.len())
73        };
74
75        if let Some(addr) = self.address.get(index) {
76            return Ok(addr.to_owned());
77        }
78        Err(ConsensusError::Other(
79            "The address list mismatch propose weight list".to_string(),
80        ))
81    }
82
83    /// Calculate whether the sum of vote weights from bitmap is above 2/3.
84    pub fn is_above_threshold(&self, bitmap: &[u8]) -> ConsensusResult<bool> {
85        let bitmap = BitVec::from_bytes(bitmap);
86        let mut acc = 0u64;
87
88        for node in bitmap.iter().zip(self.address.iter()) {
89            if node.0 {
90                if let Some(weight) = self.vote_weight_map.get(node.1) {
91                    acc += u64::from(*weight);
92                } else {
93                    return Err(ConsensusError::Other(format!(
94                        "Lose {:?} vote weight",
95                        node.1.clone()
96                    )));
97                }
98            }
99        }
100
101        Ok(acc * 3 > self.vote_weight_sum * 2)
102    }
103
104    pub fn get_voters(&self, bitmap: &[u8]) -> ConsensusResult<Vec<Address>> {
105        let bitmap = BitVec::from_bytes(bitmap);
106        let voters = bitmap
107            .iter()
108            .zip(self.address.iter())
109            .filter(|node| node.0)
110            .map(|node| node.1.clone())
111            .collect::<Vec<_>>();
112        Ok(voters)
113    }
114
115    /// If the given address is in the current authority list.
116    pub fn contains(&self, address: &Address) -> bool {
117        self.address.contains(address)
118    }
119
120    /// Get the sum of the vote weights in the current height.
121    pub fn get_vote_weight_sum(&self) -> u64 {
122        self.vote_weight_sum
123    }
124
125    /// Clear the HeightAuthorityManage, removing all values.
126    pub fn flush(&mut self) {
127        self.address.clear();
128        self.propose_weights.clear();
129        self.vote_weight_map.clear();
130        self.propose_weight_sum = 0;
131        self.vote_weight_sum = 0;
132    }
133
134    /// Get the length of the current authority list.
135    pub fn len(&self) -> usize {
136        self.address.len()
137    }
138
139    pub fn get_address_ref(&self) -> &Vec<Address> {
140        &self.address
141    }
142}
143
144/// Give the validators list and bitmap, returns the activated validators, the authority list MUST
145/// be sorted
146pub fn extract_voters(
147    authority_list: &mut [Node],
148    address_bitmap: &bytes::Bytes,
149) -> ConsensusResult<Vec<Address>> {
150    authority_list.sort();
151    let bitmap = BitVec::from_bytes(address_bitmap);
152    let voters: Vec<Address> = bitmap
153        .iter()
154        .zip(authority_list.iter())
155        .filter(|pair| pair.0) //the bitmap must hit
156        .map(|pair| pair.1.address.clone()) //get the corresponding address
157        .collect::<Vec<_>>();
158    Ok(voters)
159}
160
161/// Get the leader address of the height and the round, the authority list MUST be sorted.
162pub fn get_leader(height: u64, round: u64, mut authority_list: Vec<Node>) -> Address {
163    authority_list.sort();
164    let mut weight_sum = 0;
165    let mut propose_weights = Vec::new();
166    for node in authority_list.iter() {
167        weight_sum += node.propose_weight;
168        propose_weights.push(node.propose_weight as u64);
169    }
170
171    let index = if cfg!(feature = "random_leader") {
172        get_random_proposer_index(height + round, &propose_weights, weight_sum as u64)
173    } else {
174        rotation_leader_index(height, round, authority_list.len())
175    };
176
177    authority_list[index].address.clone()
178}
179
180fn rotation_leader_index(height: u64, round: u64, authority_len: usize) -> usize {
181    let len = authority_len as u32;
182    let prime_num = *get_primes_less_than_x(len).last().unwrap_or(&1) as u64;
183    let res = (height * prime_num + round) % (len as u64);
184    res as usize
185}
186
187#[cfg(test)]
188mod test {
189    use bit_vec::BitVec;
190    use bytes::Bytes;
191    use rand::random;
192
193    use crate::error::ConsensusError;
194    use crate::extract_voters;
195    use crate::types::{Address, Node};
196    use crate::utils::auth_manage::AuthorityManage;
197
198    fn gen_address() -> Address {
199        Address::from((0..32).map(|_| random::<u8>()).collect::<Vec<_>>())
200    }
201
202    fn gen_auth_list(len: usize) -> Vec<Node> {
203        if len == 0 {
204            return vec![];
205        }
206
207        let mut authority_list = Vec::new();
208        for _ in 0..len {
209            authority_list.push(gen_node(gen_address(), random::<u32>(), random::<u32>()));
210        }
211        authority_list
212    }
213
214    fn gen_node(addr: Address, propose_weight: u32, vote_weight: u32) -> Node {
215        let mut node = Node::new(addr);
216        node.set_propose_weight(propose_weight);
217        node.set_vote_weight(vote_weight);
218        node
219    }
220
221    fn gen_bitmap(len: usize, nbits: Vec<usize>) -> BitVec {
222        let mut bv = BitVec::from_elem(len, false);
223        for n in nbits.into_iter() {
224            bv.set(n, true);
225        }
226        bv
227    }
228
229    #[test]
230    fn test_vote_weight() {
231        let mut authority_list = gen_auth_list(0);
232        let mut authority_manage = AuthorityManage::new();
233        authority_manage.update(&mut authority_list);
234
235        for node in authority_list.iter() {
236            assert_eq!(
237                authority_manage.get_vote_weight(&node.address),
238                Err(ConsensusError::InvalidAddress)
239            );
240        }
241
242        let mut auth_len = random::<u8>();
243        while auth_len == 0 {
244            auth_len = random::<u8>();
245        }
246        authority_manage.update(&mut gen_auth_list(auth_len as usize));
247
248        for node in authority_list.iter() {
249            assert_eq!(
250                *authority_manage.get_vote_weight(&node.address).unwrap(),
251                node.propose_weight
252            );
253        }
254    }
255
256    #[test]
257    fn test_update() {
258        let mut authority_list = gen_auth_list(random::<u8>() as usize);
259        let mut auth_manage = AuthorityManage::new();
260        auth_manage.update(&mut authority_list);
261        assert_eq!(
262            auth_manage.address,
263            authority_list
264                .into_iter()
265                .map(|node| node.address)
266                .collect::<Vec<Address>>()
267        );
268    }
269
270    #[test]
271    fn test_vote_threshold() {
272        let mut authority_list = vec![
273            gen_node(gen_address(), 1u32, 1u32),
274            gen_node(gen_address(), 1u32, 1u32),
275            gen_node(gen_address(), 1u32, 1u32),
276            gen_node(gen_address(), 1u32, 1u32),
277        ];
278        authority_list.sort();
279        let mut authority = AuthorityManage::new();
280        authority.update(&mut authority_list);
281
282        for i in 0..4 {
283            let bit_map = gen_bitmap(4, vec![i]);
284            let res = authority.is_above_threshold(Bytes::from(bit_map.to_bytes()).as_ref());
285            assert!(!res.unwrap())
286        }
287
288        let tmp = vec![vec![1, 2], vec![1, 3], vec![2, 3], vec![0, 1], vec![0, 2]];
289        for i in tmp.into_iter() {
290            let bit_map = gen_bitmap(4, i);
291            let res = authority.is_above_threshold(Bytes::from(bit_map.to_bytes()).as_ref());
292            assert!(!res.unwrap())
293        }
294
295        let tmp = vec![vec![0, 1, 2], vec![0, 1, 3], vec![1, 2, 3]];
296        for i in tmp.into_iter() {
297            let bit_map = gen_bitmap(4, i);
298            let res = authority.is_above_threshold(Bytes::from(bit_map.to_bytes()).as_ref());
299            assert!(res.unwrap())
300        }
301
302        let bit_map = gen_bitmap(4, vec![0, 1, 2, 3]);
303        let res = authority.is_above_threshold(Bytes::from(bit_map.to_bytes()).as_ref());
304        assert!(res.unwrap())
305    }
306
307    #[test]
308    fn test_bitmap() {
309        let len = random::<u8>() as usize;
310        let bitmap = (0..len).map(|_| random::<bool>()).collect::<Vec<_>>();
311        let mut bv = BitVec::from_elem(len, false);
312        for (index, is_vote) in bitmap.iter().enumerate() {
313            if *is_vote {
314                bv.set(index, true);
315            }
316        }
317
318        let tmp = Bytes::from(bv.to_bytes());
319        let output = BitVec::from_bytes(tmp.as_ref());
320
321        for item in output.iter().zip(bitmap.iter()) {
322            assert_eq!(item.0, *item.1);
323        }
324    }
325
326    #[test]
327    fn test_get_voters() {
328        let auth_list = (0..4).map(|_| gen_address()).collect::<Vec<_>>();
329        let bitmap = BitVec::from_bytes(&[0b1010_0000]);
330        let voters = bitmap
331            .iter()
332            .zip(auth_list.iter())
333            .filter(|node| node.0)
334            .map(|node| node.1.clone())
335            .collect::<Vec<_>>();
336
337        assert_eq!(voters.len(), 2);
338        assert_eq!(voters[0], auth_list[0]);
339        assert_eq!(voters[1], auth_list[2]);
340    }
341
342    #[test]
343    fn test_poll_leader() {
344        let mut authority_list = vec![
345            gen_node(gen_address(), 1u32, 1u32),
346            gen_node(gen_address(), 1u32, 1u32),
347            gen_node(gen_address(), 1u32, 1u32),
348            gen_node(gen_address(), 1u32, 1u32),
349        ];
350        authority_list.sort();
351        let mut authority = AuthorityManage::new();
352        authority.update(&mut authority_list);
353
354        assert_eq!(
355            authority.get_proposer(1, 0).unwrap(),
356            authority_list[3].address
357        );
358        assert_eq!(
359            authority.get_proposer(1, 1).unwrap(),
360            authority_list[0].address
361        );
362        assert_eq!(
363            authority.get_proposer(2, 0).unwrap(),
364            authority_list[2].address
365        );
366        assert_eq!(
367            authority.get_proposer(2, 2).unwrap(),
368            authority_list[0].address
369        );
370        assert_eq!(
371            authority.get_proposer(3, 0).unwrap(),
372            authority_list[1].address
373        );
374        assert_eq!(
375            authority.get_proposer(3, 1).unwrap(),
376            authority_list[2].address
377        );
378    }
379
380    #[test]
381    fn test_extract_voters() {
382        let mut auth_list = gen_auth_list(10);
383        let mut origin_auth_list = auth_list.clone();
384        origin_auth_list.sort();
385        let bit_map = gen_bitmap(10, vec![0, 1, 2]);
386        let res = extract_voters(&mut auth_list, &Bytes::from(bit_map.to_bytes())).unwrap();
387
388        assert_eq!(res.len(), 3);
389
390        for (index, address) in res.iter().enumerate() {
391            assert_eq!(
392                origin_auth_list.get(index).unwrap().address,
393                address.clone()
394            );
395        }
396    }
397}