gemachain_runtime/
vote_account.rs

1use {
2    itertools::Itertools,
3    serde::de::{Deserialize, Deserializer},
4    serde::ser::{Serialize, Serializer},
5    gemachain_sdk::{
6        account::Account, account::AccountSharedData, instruction::InstructionError, pubkey::Pubkey,
7    },
8    gemachain_vote_program::vote_state::VoteState,
9    std::{
10        cmp::Ordering,
11        collections::{hash_map::Entry, HashMap},
12        iter::FromIterator,
13        sync::{Arc, Once, RwLock, RwLockReadGuard},
14    },
15};
16
17// The value here does not matter. It will be overwritten
18// at the first call to VoteAccount::vote_state().
19const INVALID_VOTE_STATE: Result<VoteState, InstructionError> =
20    Err(InstructionError::InvalidAccountData);
21
22#[derive(Clone, Debug, Default, PartialEq, AbiExample)]
23pub struct VoteAccount(Arc<VoteAccountInner>);
24
25#[derive(Debug, AbiExample)]
26struct VoteAccountInner {
27    account: Account,
28    vote_state: RwLock<Result<VoteState, InstructionError>>,
29    vote_state_once: Once,
30}
31
32#[derive(Debug, AbiExample)]
33pub struct VoteAccounts {
34    vote_accounts: Arc<HashMap<Pubkey, (/*stake:*/ u64, VoteAccount)>>,
35    // Inner Arc is meant to implement copy-on-write semantics as opposed to
36    // sharing mutations (hence RwLock<Arc<...>> instead of Arc<RwLock<...>>).
37    staked_nodes: RwLock<
38        Arc<
39            HashMap<
40                Pubkey, // VoteAccount.vote_state.node_pubkey.
41                u64,    // Total stake across all vote-accounts.
42            >,
43        >,
44    >,
45    staked_nodes_once: Once,
46}
47
48impl VoteAccount {
49    pub(crate) fn carats(&self) -> u64 {
50        self.0.account.carats
51    }
52
53    pub fn vote_state(&self) -> RwLockReadGuard<Result<VoteState, InstructionError>> {
54        let inner = &self.0;
55        inner.vote_state_once.call_once(|| {
56            let vote_state = VoteState::deserialize(&inner.account.data);
57            *inner.vote_state.write().unwrap() = vote_state;
58        });
59        inner.vote_state.read().unwrap()
60    }
61
62    /// VoteState.node_pubkey of this vote-account.
63    fn node_pubkey(&self) -> Option<Pubkey> {
64        Some(self.vote_state().as_ref().ok()?.node_pubkey)
65    }
66}
67
68impl VoteAccounts {
69    pub fn staked_nodes(&self) -> Arc<HashMap<Pubkey, u64>> {
70        self.staked_nodes_once.call_once(|| {
71            let staked_nodes = self
72                .vote_accounts
73                .values()
74                .filter(|(stake, _)| *stake != 0)
75                .filter_map(|(stake, vote_account)| {
76                    let node_pubkey = vote_account.node_pubkey()?;
77                    Some((node_pubkey, stake))
78                })
79                .into_grouping_map()
80                .aggregate(|acc, _node_pubkey, stake| Some(acc.unwrap_or_default() + stake));
81            *self.staked_nodes.write().unwrap() = Arc::new(staked_nodes)
82        });
83        self.staked_nodes.read().unwrap().clone()
84    }
85
86    pub fn get(&self, pubkey: &Pubkey) -> Option<&(/*stake:*/ u64, VoteAccount)> {
87        self.vote_accounts.get(pubkey)
88    }
89
90    pub(crate) fn iter(&self) -> impl Iterator<Item = (&Pubkey, &(u64, VoteAccount))> {
91        self.vote_accounts.iter()
92    }
93
94    pub(crate) fn insert(&mut self, pubkey: Pubkey, (stake, vote_account): (u64, VoteAccount)) {
95        self.add_node_stake(stake, &vote_account);
96        let vote_accounts = Arc::make_mut(&mut self.vote_accounts);
97        if let Some((stake, vote_account)) = vote_accounts.insert(pubkey, (stake, vote_account)) {
98            self.sub_node_stake(stake, &vote_account);
99        }
100    }
101
102    pub(crate) fn remove(&mut self, pubkey: &Pubkey) -> Option<(u64, VoteAccount)> {
103        let vote_accounts = Arc::make_mut(&mut self.vote_accounts);
104        let entry = vote_accounts.remove(pubkey);
105        if let Some((stake, ref vote_account)) = entry {
106            self.sub_node_stake(stake, vote_account);
107        }
108        entry
109    }
110
111    pub(crate) fn add_stake(&mut self, pubkey: &Pubkey, delta: u64) {
112        let vote_accounts = Arc::make_mut(&mut self.vote_accounts);
113        if let Some((stake, vote_account)) = vote_accounts.get_mut(pubkey) {
114            *stake += delta;
115            let vote_account = vote_account.clone();
116            self.add_node_stake(delta, &vote_account);
117        }
118    }
119
120    pub(crate) fn sub_stake(&mut self, pubkey: &Pubkey, delta: u64) {
121        let vote_accounts = Arc::make_mut(&mut self.vote_accounts);
122        if let Some((stake, vote_account)) = vote_accounts.get_mut(pubkey) {
123            *stake = stake
124                .checked_sub(delta)
125                .expect("subtraction value exceeds account's stake");
126            let vote_account = vote_account.clone();
127            self.sub_node_stake(delta, &vote_account);
128        }
129    }
130
131    fn add_node_stake(&mut self, stake: u64, vote_account: &VoteAccount) {
132        if stake != 0 && self.staked_nodes_once.is_completed() {
133            if let Some(node_pubkey) = vote_account.node_pubkey() {
134                let mut staked_nodes = self.staked_nodes.write().unwrap();
135                let staked_nodes = Arc::make_mut(&mut staked_nodes);
136                staked_nodes
137                    .entry(node_pubkey)
138                    .and_modify(|s| *s += stake)
139                    .or_insert(stake);
140            }
141        }
142    }
143
144    fn sub_node_stake(&mut self, stake: u64, vote_account: &VoteAccount) {
145        if stake != 0 && self.staked_nodes_once.is_completed() {
146            if let Some(node_pubkey) = vote_account.node_pubkey() {
147                let mut staked_nodes = self.staked_nodes.write().unwrap();
148                let staked_nodes = Arc::make_mut(&mut staked_nodes);
149                match staked_nodes.entry(node_pubkey) {
150                    Entry::Vacant(_) => panic!("this should not happen!"),
151                    Entry::Occupied(mut entry) => match entry.get().cmp(&stake) {
152                        Ordering::Less => panic!("subtraction value exceeds node's stake"),
153                        Ordering::Equal => {
154                            entry.remove_entry();
155                        }
156                        Ordering::Greater => *entry.get_mut() -= stake,
157                    },
158                }
159            }
160        }
161    }
162}
163
164impl Serialize for VoteAccount {
165    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
166    where
167        S: Serializer,
168    {
169        self.0.account.serialize(serializer)
170    }
171}
172
173impl<'de> Deserialize<'de> for VoteAccount {
174    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
175    where
176        D: Deserializer<'de>,
177    {
178        let account = Account::deserialize(deserializer)?;
179        Ok(Self::from(account))
180    }
181}
182
183impl From<AccountSharedData> for VoteAccount {
184    fn from(account: AccountSharedData) -> Self {
185        Self(Arc::new(VoteAccountInner::from(account)))
186    }
187}
188
189impl From<Account> for VoteAccount {
190    fn from(account: Account) -> Self {
191        Self(Arc::new(VoteAccountInner::from(account)))
192    }
193}
194
195impl From<AccountSharedData> for VoteAccountInner {
196    fn from(account: AccountSharedData) -> Self {
197        Self::from(Account::from(account))
198    }
199}
200
201impl From<Account> for VoteAccountInner {
202    fn from(account: Account) -> Self {
203        Self {
204            account,
205            vote_state: RwLock::new(INVALID_VOTE_STATE),
206            vote_state_once: Once::new(),
207        }
208    }
209}
210
211impl Default for VoteAccountInner {
212    fn default() -> Self {
213        Self {
214            account: Account::default(),
215            vote_state: RwLock::new(INVALID_VOTE_STATE),
216            vote_state_once: Once::new(),
217        }
218    }
219}
220
221impl PartialEq<VoteAccountInner> for VoteAccountInner {
222    fn eq(&self, other: &Self) -> bool {
223        self.account == other.account
224    }
225}
226
227impl Default for VoteAccounts {
228    fn default() -> Self {
229        Self {
230            vote_accounts: Arc::default(),
231            staked_nodes: RwLock::default(),
232            staked_nodes_once: Once::new(),
233        }
234    }
235}
236
237impl Clone for VoteAccounts {
238    fn clone(&self) -> Self {
239        if self.staked_nodes_once.is_completed() {
240            let staked_nodes = self.staked_nodes.read().unwrap().clone();
241            let other = Self {
242                vote_accounts: self.vote_accounts.clone(),
243                staked_nodes: RwLock::new(staked_nodes),
244                staked_nodes_once: Once::new(),
245            };
246            other.staked_nodes_once.call_once(|| {});
247            other
248        } else {
249            Self {
250                vote_accounts: self.vote_accounts.clone(),
251                staked_nodes: RwLock::default(),
252                staked_nodes_once: Once::new(),
253            }
254        }
255    }
256}
257
258impl PartialEq<VoteAccounts> for VoteAccounts {
259    fn eq(&self, other: &Self) -> bool {
260        self.vote_accounts == other.vote_accounts
261    }
262}
263
264type VoteAccountsHashMap = HashMap<Pubkey, (/*stake:*/ u64, VoteAccount)>;
265
266impl From<Arc<VoteAccountsHashMap>> for VoteAccounts {
267    fn from(vote_accounts: Arc<VoteAccountsHashMap>) -> Self {
268        Self {
269            vote_accounts,
270            staked_nodes: RwLock::default(),
271            staked_nodes_once: Once::new(),
272        }
273    }
274}
275
276impl AsRef<VoteAccountsHashMap> for VoteAccounts {
277    fn as_ref(&self) -> &VoteAccountsHashMap {
278        &self.vote_accounts
279    }
280}
281
282impl From<&VoteAccounts> for Arc<VoteAccountsHashMap> {
283    fn from(vote_accounts: &VoteAccounts) -> Self {
284        Arc::clone(&vote_accounts.vote_accounts)
285    }
286}
287
288impl FromIterator<(Pubkey, (/*stake:*/ u64, VoteAccount))> for VoteAccounts {
289    fn from_iter<I>(iter: I) -> Self
290    where
291        I: IntoIterator<Item = (Pubkey, (u64, VoteAccount))>,
292    {
293        Self::from(Arc::new(HashMap::from_iter(iter)))
294    }
295}
296
297impl Serialize for VoteAccounts {
298    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
299    where
300        S: Serializer,
301    {
302        self.vote_accounts.serialize(serializer)
303    }
304}
305
306impl<'de> Deserialize<'de> for VoteAccounts {
307    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
308    where
309        D: Deserializer<'de>,
310    {
311        let vote_accounts = VoteAccountsHashMap::deserialize(deserializer)?;
312        Ok(Self::from(Arc::new(vote_accounts)))
313    }
314}
315
316#[cfg(test)]
317mod tests {
318    use super::*;
319    use bincode::Options;
320    use rand::Rng;
321    use gemachain_sdk::{pubkey::Pubkey, sysvar::clock::Clock};
322    use gemachain_vote_program::vote_state::{VoteInit, VoteStateVersions};
323    use std::iter::repeat_with;
324
325    fn new_rand_vote_account<R: Rng>(
326        rng: &mut R,
327        node_pubkey: Option<Pubkey>,
328    ) -> (Account, VoteState) {
329        let vote_init = VoteInit {
330            node_pubkey: node_pubkey.unwrap_or_else(Pubkey::new_unique),
331            authorized_voter: Pubkey::new_unique(),
332            authorized_withdrawer: Pubkey::new_unique(),
333            commission: rng.gen(),
334        };
335        let clock = Clock {
336            slot: rng.gen(),
337            epoch_start_timestamp: rng.gen(),
338            epoch: rng.gen(),
339            leader_schedule_epoch: rng.gen(),
340            unix_timestamp: rng.gen(),
341        };
342        let vote_state = VoteState::new(&vote_init, &clock);
343        let account = Account::new_data(
344            rng.gen(), // carats
345            &VoteStateVersions::new_current(vote_state.clone()),
346            &Pubkey::new_unique(), // owner
347        )
348        .unwrap();
349        (account, vote_state)
350    }
351
352    fn new_rand_vote_accounts<R: Rng>(
353        rng: &mut R,
354        num_nodes: usize,
355    ) -> impl Iterator<Item = (Pubkey, (/*stake:*/ u64, VoteAccount))> + '_ {
356        let nodes: Vec<_> = repeat_with(Pubkey::new_unique).take(num_nodes).collect();
357        repeat_with(move || {
358            let node = nodes[rng.gen_range(0, nodes.len())];
359            let (account, _) = new_rand_vote_account(rng, Some(node));
360            let stake = rng.gen_range(0, 997);
361            (Pubkey::new_unique(), (stake, VoteAccount::from(account)))
362        })
363    }
364
365    fn staked_nodes<'a, I>(vote_accounts: I) -> HashMap<Pubkey, u64>
366    where
367        I: IntoIterator<Item = &'a (Pubkey, (u64, VoteAccount))>,
368    {
369        let mut staked_nodes = HashMap::new();
370        for (_, (stake, vote_account)) in vote_accounts
371            .into_iter()
372            .filter(|(_, (stake, _))| *stake != 0)
373        {
374            if let Some(node_pubkey) = vote_account.node_pubkey() {
375                staked_nodes
376                    .entry(node_pubkey)
377                    .and_modify(|s| *s += *stake)
378                    .or_insert(*stake);
379            }
380        }
381        staked_nodes
382    }
383
384    #[test]
385    fn test_vote_account() {
386        let mut rng = rand::thread_rng();
387        let (account, vote_state) = new_rand_vote_account(&mut rng, None);
388        let carats = account.carats;
389        let vote_account = VoteAccount::from(account);
390        assert_eq!(carats, vote_account.carats());
391        assert_eq!(vote_state, *vote_account.vote_state().as_ref().unwrap());
392        // 2nd call to .vote_state() should return the cached value.
393        assert_eq!(vote_state, *vote_account.vote_state().as_ref().unwrap());
394    }
395
396    #[test]
397    fn test_vote_account_serialize() {
398        let mut rng = rand::thread_rng();
399        let (account, vote_state) = new_rand_vote_account(&mut rng, None);
400        let vote_account = VoteAccount::from(account.clone());
401        assert_eq!(vote_state, *vote_account.vote_state().as_ref().unwrap());
402        // Assert than VoteAccount has the same wire format as Account.
403        assert_eq!(
404            bincode::serialize(&account).unwrap(),
405            bincode::serialize(&vote_account).unwrap()
406        );
407    }
408
409    #[test]
410    fn test_vote_account_deserialize() {
411        let mut rng = rand::thread_rng();
412        let (account, vote_state) = new_rand_vote_account(&mut rng, None);
413        let data = bincode::serialize(&account).unwrap();
414        let vote_account = VoteAccount::from(account);
415        assert_eq!(vote_state, *vote_account.vote_state().as_ref().unwrap());
416        let other_vote_account: VoteAccount = bincode::deserialize(&data).unwrap();
417        assert_eq!(vote_account, other_vote_account);
418        assert_eq!(
419            vote_state,
420            *other_vote_account.vote_state().as_ref().unwrap()
421        );
422    }
423
424    #[test]
425    fn test_vote_account_round_trip() {
426        let mut rng = rand::thread_rng();
427        let (account, vote_state) = new_rand_vote_account(&mut rng, None);
428        let vote_account = VoteAccount::from(account);
429        assert_eq!(vote_state, *vote_account.vote_state().as_ref().unwrap());
430        let data = bincode::serialize(&vote_account).unwrap();
431        let other_vote_account: VoteAccount = bincode::deserialize(&data).unwrap();
432        // Assert that serialize->deserialized returns the same VoteAccount.
433        assert_eq!(vote_account, other_vote_account);
434        assert_eq!(
435            vote_state,
436            *other_vote_account.vote_state().as_ref().unwrap()
437        );
438    }
439
440    #[test]
441    fn test_vote_accounts_serialize() {
442        let mut rng = rand::thread_rng();
443        let vote_accounts_hash_map: HashMap<Pubkey, (u64, VoteAccount)> =
444            new_rand_vote_accounts(&mut rng, 64).take(1024).collect();
445        let vote_accounts = VoteAccounts::from(Arc::new(vote_accounts_hash_map.clone()));
446        assert!(vote_accounts.staked_nodes().len() > 32);
447        assert_eq!(
448            bincode::serialize(&vote_accounts).unwrap(),
449            bincode::serialize(&vote_accounts_hash_map).unwrap(),
450        );
451        assert_eq!(
452            bincode::options().serialize(&vote_accounts).unwrap(),
453            bincode::options()
454                .serialize(&vote_accounts_hash_map)
455                .unwrap(),
456        )
457    }
458
459    #[test]
460    fn test_vote_accounts_deserialize() {
461        let mut rng = rand::thread_rng();
462        let vote_accounts_hash_map: HashMap<Pubkey, (u64, VoteAccount)> =
463            new_rand_vote_accounts(&mut rng, 64).take(1024).collect();
464        let data = bincode::serialize(&vote_accounts_hash_map).unwrap();
465        let vote_accounts: VoteAccounts = bincode::deserialize(&data).unwrap();
466        assert!(vote_accounts.staked_nodes().len() > 32);
467        assert_eq!(*vote_accounts.vote_accounts, vote_accounts_hash_map);
468        let data = bincode::options()
469            .serialize(&vote_accounts_hash_map)
470            .unwrap();
471        let vote_accounts: VoteAccounts = bincode::options().deserialize(&data).unwrap();
472        assert_eq!(*vote_accounts.vote_accounts, vote_accounts_hash_map);
473    }
474
475    #[test]
476    fn test_staked_nodes() {
477        let mut rng = rand::thread_rng();
478        let mut accounts: Vec<_> = new_rand_vote_accounts(&mut rng, 64).take(1024).collect();
479        let mut vote_accounts = VoteAccounts::default();
480        // Add vote accounts.
481        for (k, (pubkey, (stake, vote_account))) in accounts.iter().enumerate() {
482            vote_accounts.insert(*pubkey, (*stake, vote_account.clone()));
483            if (k + 1) % 128 == 0 {
484                assert_eq!(
485                    staked_nodes(&accounts[..k + 1]),
486                    *vote_accounts.staked_nodes()
487                );
488            }
489        }
490        // Remove some of the vote accounts.
491        for k in 0..256 {
492            let index = rng.gen_range(0, accounts.len());
493            let (pubkey, (_, _)) = accounts.swap_remove(index);
494            vote_accounts.remove(&pubkey);
495            if (k + 1) % 32 == 0 {
496                assert_eq!(staked_nodes(&accounts), *vote_accounts.staked_nodes());
497            }
498        }
499        // Modify the stakes for some of the accounts.
500        for k in 0..2048 {
501            let index = rng.gen_range(0, accounts.len());
502            let (pubkey, (stake, _)) = &mut accounts[index];
503            let new_stake = rng.gen_range(0, 997);
504            if new_stake < *stake {
505                vote_accounts.sub_stake(pubkey, *stake - new_stake);
506            } else {
507                vote_accounts.add_stake(pubkey, new_stake - *stake);
508            }
509            *stake = new_stake;
510            if (k + 1) % 128 == 0 {
511                assert_eq!(staked_nodes(&accounts), *vote_accounts.staked_nodes());
512            }
513        }
514        // Remove everything.
515        while !accounts.is_empty() {
516            let index = rng.gen_range(0, accounts.len());
517            let (pubkey, (_, _)) = accounts.swap_remove(index);
518            vote_accounts.remove(&pubkey);
519            if accounts.len() % 32 == 0 {
520                assert_eq!(staked_nodes(&accounts), *vote_accounts.staked_nodes());
521            }
522        }
523        assert!(vote_accounts.staked_nodes.read().unwrap().is_empty());
524    }
525
526    // Asserts that returned staked-nodes are copy-on-write references.
527    #[test]
528    fn test_staked_nodes_cow() {
529        let mut rng = rand::thread_rng();
530        let mut accounts = new_rand_vote_accounts(&mut rng, 64);
531        // Add vote accounts.
532        let mut vote_accounts = VoteAccounts::default();
533        for (pubkey, (stake, vote_account)) in (&mut accounts).take(1024) {
534            vote_accounts.insert(pubkey, (stake, vote_account));
535        }
536        let staked_nodes = vote_accounts.staked_nodes();
537        let (pubkey, (more_stake, vote_account)) =
538            accounts.find(|(_, (stake, _))| *stake != 0).unwrap();
539        let node_pubkey = vote_account.node_pubkey().unwrap();
540        vote_accounts.insert(pubkey, (more_stake, vote_account));
541        assert_ne!(staked_nodes, vote_accounts.staked_nodes());
542        assert_eq!(
543            vote_accounts.staked_nodes()[&node_pubkey],
544            more_stake + staked_nodes.get(&node_pubkey).copied().unwrap_or_default()
545        );
546        for (pubkey, stake) in vote_accounts.staked_nodes().iter() {
547            if *pubkey != node_pubkey {
548                assert_eq!(*stake, staked_nodes[pubkey]);
549            } else {
550                assert_eq!(
551                    *stake,
552                    more_stake + staked_nodes.get(pubkey).copied().unwrap_or_default()
553                );
554            }
555        }
556    }
557
558    // Asserts that returned vote-accounts are copy-on-write references.
559    #[test]
560    fn test_vote_accounts_cow() {
561        let mut rng = rand::thread_rng();
562        let mut accounts = new_rand_vote_accounts(&mut rng, 64);
563        // Add vote accounts.
564        let mut vote_accounts = VoteAccounts::default();
565        for (pubkey, (stake, vote_account)) in (&mut accounts).take(1024) {
566            vote_accounts.insert(pubkey, (stake, vote_account));
567        }
568        let vote_accounts_hashmap = Arc::<VoteAccountsHashMap>::from(&vote_accounts);
569        assert_eq!(vote_accounts_hashmap, vote_accounts.vote_accounts);
570        assert!(Arc::ptr_eq(
571            &vote_accounts_hashmap,
572            &vote_accounts.vote_accounts
573        ));
574        let (pubkey, (more_stake, vote_account)) =
575            accounts.find(|(_, (stake, _))| *stake != 0).unwrap();
576        vote_accounts.insert(pubkey, (more_stake, vote_account.clone()));
577        assert!(!Arc::ptr_eq(
578            &vote_accounts_hashmap,
579            &vote_accounts.vote_accounts
580        ));
581        assert_ne!(vote_accounts_hashmap, vote_accounts.vote_accounts);
582        let other = (more_stake, vote_account);
583        for (pk, value) in vote_accounts.iter() {
584            if *pk != pubkey {
585                assert_eq!(value, &vote_accounts_hashmap[pk]);
586            } else {
587                assert_eq!(value, &other);
588            }
589        }
590    }
591}