solana_vote_interface/
authorized_voters.rs

1#[cfg(feature = "dev-context-only-utils")]
2use arbitrary::Arbitrary;
3#[cfg(feature = "serde")]
4use serde_derive::{Deserialize, Serialize};
5use {solana_clock::Epoch, solana_pubkey::Pubkey, std::collections::BTreeMap};
6
7#[cfg_attr(feature = "frozen-abi", derive(solana_frozen_abi_macro::AbiExample))]
8#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
9#[derive(Debug, Default, PartialEq, Eq, Clone)]
10#[cfg_attr(feature = "dev-context-only-utils", derive(Arbitrary))]
11pub struct AuthorizedVoters {
12    authorized_voters: BTreeMap<Epoch, Pubkey>,
13}
14
15impl AuthorizedVoters {
16    pub fn new(epoch: Epoch, pubkey: Pubkey) -> Self {
17        let mut authorized_voters = BTreeMap::new();
18        authorized_voters.insert(epoch, pubkey);
19        Self { authorized_voters }
20    }
21
22    pub fn get_authorized_voter(&self, epoch: Epoch) -> Option<Pubkey> {
23        self.get_or_calculate_authorized_voter_for_epoch(epoch)
24            .map(|(pubkey, _)| pubkey)
25    }
26
27    pub fn get_and_cache_authorized_voter_for_epoch(&mut self, epoch: Epoch) -> Option<Pubkey> {
28        let res = self.get_or_calculate_authorized_voter_for_epoch(epoch);
29
30        res.map(|(pubkey, existed)| {
31            if !existed {
32                self.authorized_voters.insert(epoch, pubkey);
33            }
34            pubkey
35        })
36    }
37
38    pub fn insert(&mut self, epoch: Epoch, authorized_voter: Pubkey) {
39        self.authorized_voters.insert(epoch, authorized_voter);
40    }
41
42    pub fn purge_authorized_voters(&mut self, current_epoch: Epoch) -> bool {
43        // Iterate through the keys in order, filtering out the ones
44        // less than the current epoch
45        let expired_keys: Vec<_> = self
46            .authorized_voters
47            .range(0..current_epoch)
48            .map(|(authorized_epoch, _)| *authorized_epoch)
49            .collect();
50
51        for key in expired_keys {
52            self.authorized_voters.remove(&key);
53        }
54
55        // Have to uphold this invariant b/c this is
56        // 1) The check for whether the vote state is initialized
57        // 2) How future authorized voters for uninitialized epochs are set
58        //    by this function
59        assert!(!self.authorized_voters.is_empty());
60        true
61    }
62
63    pub fn is_empty(&self) -> bool {
64        self.authorized_voters.is_empty()
65    }
66
67    pub fn first(&self) -> Option<(&u64, &Pubkey)> {
68        self.authorized_voters.iter().next()
69    }
70
71    pub fn last(&self) -> Option<(&u64, &Pubkey)> {
72        self.authorized_voters.iter().next_back()
73    }
74
75    pub fn len(&self) -> usize {
76        self.authorized_voters.len()
77    }
78
79    pub fn contains(&self, epoch: Epoch) -> bool {
80        self.authorized_voters.contains_key(&epoch)
81    }
82
83    pub fn iter(&self) -> std::collections::btree_map::Iter<Epoch, Pubkey> {
84        self.authorized_voters.iter()
85    }
86
87    // Returns the authorized voter at the given epoch if the epoch is >= the
88    // current epoch, and a bool indicating whether the entry for this epoch
89    // exists in the self.authorized_voter map
90    fn get_or_calculate_authorized_voter_for_epoch(&self, epoch: Epoch) -> Option<(Pubkey, bool)> {
91        let res = self.authorized_voters.get(&epoch);
92        if res.is_none() {
93            // If no authorized voter has been set yet for this epoch,
94            // this must mean the authorized voter remains unchanged
95            // from the latest epoch before this one
96            let res = self.authorized_voters.range(0..epoch).next_back();
97
98            /*
99            if res.is_none() {
100                warn!(
101                    "Tried to query for the authorized voter of an epoch earlier
102                    than the current epoch. Earlier epochs have been purged"
103                );
104            }
105            */
106
107            res.map(|(_, pubkey)| (*pubkey, false))
108        } else {
109            res.map(|pubkey| (*pubkey, true))
110        }
111    }
112}