gemachain_vote_program/vote_state/
mod.rs

1//! Vote state, vote program
2//! Receive and processes votes from validators
3use crate::authorized_voters::AuthorizedVoters;
4use crate::{id, vote_instruction::VoteError};
5use bincode::{deserialize, serialize_into, serialized_size, ErrorKind};
6use log::*;
7use serde_derive::{Deserialize, Serialize};
8use gemachain_sdk::{
9    account::{AccountSharedData, ReadableAccount, WritableAccount},
10    account_utils::State,
11    clock::{Epoch, Slot, UnixTimestamp},
12    epoch_schedule::MAX_LEADER_SCHEDULE_EPOCH_OFFSET,
13    hash::Hash,
14    instruction::InstructionError,
15    keyed_account::KeyedAccount,
16    pubkey::Pubkey,
17    rent::Rent,
18    slot_hashes::SlotHash,
19    sysvar::clock::Clock,
20};
21use std::boxed::Box;
22use std::cmp::Ordering;
23use std::collections::{HashSet, VecDeque};
24
25mod vote_state_0_23_5;
26pub mod vote_state_versions;
27pub use vote_state_versions::*;
28
29// Maximum number of votes to keep around, tightly coupled with epoch_schedule::MIN_SLOTS_PER_EPOCH
30pub const MAX_LOCKOUT_HISTORY: usize = 31;
31pub const INITIAL_LOCKOUT: usize = 2;
32
33// Maximum number of credits history to keep around
34pub const MAX_EPOCH_CREDITS_HISTORY: usize = 64;
35
36// Offset of VoteState::prior_voters, for determining initialization status without deserialization
37const DEFAULT_PRIOR_VOTERS_OFFSET: usize = 82;
38
39#[frozen_abi(digest = "Ch2vVEwos2EjAVqSHCyJjnN2MNX1yrpapZTGhMSCjWUH")]
40#[derive(Serialize, Default, Deserialize, Debug, PartialEq, Eq, Clone, AbiExample)]
41pub struct Vote {
42    /// A stack of votes starting with the oldest vote
43    pub slots: Vec<Slot>,
44    /// signature of the bank's state at the last slot
45    pub hash: Hash,
46    /// processing timestamp of last slot
47    pub timestamp: Option<UnixTimestamp>,
48}
49
50impl Vote {
51    pub fn new(slots: Vec<Slot>, hash: Hash) -> Self {
52        Self {
53            slots,
54            hash,
55            timestamp: None,
56        }
57    }
58
59    pub fn last_voted_slot(&self) -> Option<Slot> {
60        self.slots.last().copied()
61    }
62
63    pub fn last_voted_slot_hash(&self) -> Option<(Slot, Hash)> {
64        self.slots.last().copied().map(|slot| (slot, self.hash))
65    }
66}
67
68#[derive(Serialize, Default, Deserialize, Debug, PartialEq, Eq, Clone, AbiExample)]
69pub struct Lockout {
70    pub slot: Slot,
71    pub confirmation_count: u32,
72}
73
74impl Lockout {
75    pub fn new(slot: Slot) -> Self {
76        Self {
77            slot,
78            confirmation_count: 1,
79        }
80    }
81
82    // The number of slots for which this vote is locked
83    pub fn lockout(&self) -> u64 {
84        (INITIAL_LOCKOUT as u64).pow(self.confirmation_count)
85    }
86
87    // The last slot at which a vote is still locked out. Validators should not
88    // vote on a slot in another fork which is less than or equal to this slot
89    // to avoid having their stake slashed.
90    pub fn last_locked_out_slot(&self) -> Slot {
91        self.slot + self.lockout()
92    }
93
94    pub fn is_locked_out_at_slot(&self, slot: Slot) -> bool {
95        self.last_locked_out_slot() >= slot
96    }
97}
98
99#[derive(Default, Serialize, Deserialize, Debug, PartialEq, Eq, Clone, Copy)]
100pub struct VoteInit {
101    pub node_pubkey: Pubkey,
102    pub authorized_voter: Pubkey,
103    pub authorized_withdrawer: Pubkey,
104    pub commission: u8,
105}
106
107#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone, Copy)]
108pub enum VoteAuthorize {
109    Voter,
110    Withdrawer,
111}
112
113#[derive(Debug, Default, Serialize, Deserialize, PartialEq, Eq, Clone, AbiExample)]
114pub struct BlockTimestamp {
115    pub slot: Slot,
116    pub timestamp: UnixTimestamp,
117}
118
119// this is how many epochs a voter can be remembered for slashing
120const MAX_ITEMS: usize = 32;
121
122#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone, AbiExample)]
123pub struct CircBuf<I> {
124    buf: [I; MAX_ITEMS],
125    /// next pointer
126    idx: usize,
127    is_empty: bool,
128}
129
130impl<I: Default + Copy> Default for CircBuf<I> {
131    fn default() -> Self {
132        Self {
133            buf: [I::default(); MAX_ITEMS],
134            idx: MAX_ITEMS - 1,
135            is_empty: true,
136        }
137    }
138}
139
140impl<I> CircBuf<I> {
141    pub fn append(&mut self, item: I) {
142        // remember prior delegate and when we switched, to support later slashing
143        self.idx += 1;
144        self.idx %= MAX_ITEMS;
145
146        self.buf[self.idx] = item;
147        self.is_empty = false;
148    }
149
150    pub fn buf(&self) -> &[I; MAX_ITEMS] {
151        &self.buf
152    }
153
154    pub fn last(&self) -> Option<&I> {
155        if !self.is_empty {
156            Some(&self.buf[self.idx])
157        } else {
158            None
159        }
160    }
161}
162
163#[frozen_abi(digest = "331ZmXrmsUcwbKhzR3C1UEU6uNwZr48ExE54JDKGWA4w")]
164#[derive(Debug, Default, Serialize, Deserialize, PartialEq, Eq, Clone, AbiExample)]
165pub struct VoteState {
166    /// the node that votes in this account
167    pub node_pubkey: Pubkey,
168
169    /// the signer for withdrawals
170    pub authorized_withdrawer: Pubkey,
171    /// percentage (0-100) that represents what part of a rewards
172    ///  payout should be given to this VoteAccount
173    pub commission: u8,
174
175    pub votes: VecDeque<Lockout>,
176
177    // This usually the last Lockout which was popped from self.votes.
178    // However, it can be arbitrary slot, when being used inside Tower
179    pub root_slot: Option<Slot>,
180
181    /// the signer for vote transactions
182    authorized_voters: AuthorizedVoters,
183
184    /// history of prior authorized voters and the epochs for which
185    /// they were set, the bottom end of the range is inclusive,
186    /// the top of the range is exclusive
187    prior_voters: CircBuf<(Pubkey, Epoch, Epoch)>,
188
189    /// history of how many credits earned by the end of each epoch
190    ///  each tuple is (Epoch, credits, prev_credits)
191    epoch_credits: Vec<(Epoch, u64, u64)>,
192
193    /// most recent timestamp submitted with a vote
194    pub last_timestamp: BlockTimestamp,
195}
196
197impl VoteState {
198    pub fn new(vote_init: &VoteInit, clock: &Clock) -> Self {
199        Self {
200            node_pubkey: vote_init.node_pubkey,
201            authorized_voters: AuthorizedVoters::new(clock.epoch, vote_init.authorized_voter),
202            authorized_withdrawer: vote_init.authorized_withdrawer,
203            commission: vote_init.commission,
204            ..VoteState::default()
205        }
206    }
207
208    pub fn get_authorized_voter(&self, epoch: Epoch) -> Option<Pubkey> {
209        self.authorized_voters.get_authorized_voter(epoch)
210    }
211
212    pub fn authorized_voters(&self) -> &AuthorizedVoters {
213        &self.authorized_voters
214    }
215
216    pub fn prior_voters(&mut self) -> &CircBuf<(Pubkey, Epoch, Epoch)> {
217        &self.prior_voters
218    }
219
220    pub fn get_rent_exempt_reserve(rent: &Rent) -> u64 {
221        rent.minimum_balance(VoteState::size_of())
222    }
223
224    pub fn size_of() -> usize {
225        // Upper limit on the size of the Vote State. Equal to
226        // size_of(VoteState) when votes.len() is MAX_LOCKOUT_HISTORY
227        let vote_state = VoteStateVersions::new_current(Self::get_max_sized_vote_state());
228        serialized_size(&vote_state).unwrap() as usize
229    }
230
231    // utility function, used by Stakes, tests
232    pub fn from<T: ReadableAccount>(account: &T) -> Option<VoteState> {
233        Self::deserialize(account.data()).ok()
234    }
235
236    // utility function, used by Stakes, tests
237    pub fn to<T: WritableAccount>(versioned: &VoteStateVersions, account: &mut T) -> Option<()> {
238        Self::serialize(versioned, &mut account.data_as_mut_slice()).ok()
239    }
240
241    pub fn deserialize(input: &[u8]) -> Result<Self, InstructionError> {
242        deserialize::<VoteStateVersions>(input)
243            .map(|versioned| versioned.convert_to_current())
244            .map_err(|_| InstructionError::InvalidAccountData)
245    }
246
247    pub fn serialize(
248        versioned: &VoteStateVersions,
249        output: &mut [u8],
250    ) -> Result<(), InstructionError> {
251        serialize_into(output, versioned).map_err(|err| match *err {
252            ErrorKind::SizeLimit => InstructionError::AccountDataTooSmall,
253            _ => InstructionError::GenericError,
254        })
255    }
256
257    pub fn credits_from<T: ReadableAccount>(account: &T) -> Option<u64> {
258        Self::from(account).map(|state| state.credits())
259    }
260
261    /// returns commission split as (voter_portion, staker_portion, was_split) tuple
262    ///
263    ///  if commission calculation is 100% one way or other,
264    ///   indicate with false for was_split
265    pub fn commission_split(&self, on: u64) -> (u64, u64, bool) {
266        match self.commission.min(100) {
267            0 => (0, on, false),
268            100 => (on, 0, false),
269            split => {
270                let on = u128::from(on);
271                // Calculate mine and theirs independently and symmetrically instead of
272                // using the remainder of the other to treat them strictly equally.
273                // This is also to cancel the rewarding if either of the parties
274                // should receive only fractional carats, resulting in not being rewarded at all.
275                // Thus, note that we intentionally discard any residual fractional carats.
276                let mine = on * u128::from(split) / 100u128;
277                let theirs = on * u128::from(100 - split) / 100u128;
278
279                (mine as u64, theirs as u64, true)
280            }
281        }
282    }
283
284    fn get_max_sized_vote_state() -> VoteState {
285        let mut authorized_voters = AuthorizedVoters::default();
286        for i in 0..=MAX_LEADER_SCHEDULE_EPOCH_OFFSET {
287            authorized_voters.insert(i, gemachain_sdk::pubkey::new_rand());
288        }
289
290        VoteState {
291            votes: VecDeque::from(vec![Lockout::default(); MAX_LOCKOUT_HISTORY]),
292            root_slot: Some(std::u64::MAX),
293            epoch_credits: vec![(0, 0, 0); MAX_EPOCH_CREDITS_HISTORY],
294            authorized_voters,
295            ..Self::default()
296        }
297    }
298
299    fn check_slots_are_valid(
300        &self,
301        vote: &Vote,
302        slot_hashes: &[(Slot, Hash)],
303    ) -> Result<(), VoteError> {
304        let mut i = 0; // index into the vote's slots
305        let mut j = slot_hashes.len(); // index into the slot_hashes
306        while i < vote.slots.len() && j > 0 {
307            // find the last slot in the vote
308            if self
309                .last_voted_slot()
310                .map_or(false, |last_voted_slot| vote.slots[i] <= last_voted_slot)
311            {
312                i += 1;
313                continue;
314            }
315            if vote.slots[i] != slot_hashes[j - 1].0 {
316                j -= 1;
317                continue;
318            }
319            i += 1;
320            j -= 1;
321        }
322        if j == slot_hashes.len() {
323            debug!(
324                "{} dropped vote {:?} too old: {:?} ",
325                self.node_pubkey, vote, slot_hashes
326            );
327            return Err(VoteError::VoteTooOld);
328        }
329        if i != vote.slots.len() {
330            info!(
331                "{} dropped vote {:?} failed to match slot:  {:?}",
332                self.node_pubkey, vote, slot_hashes,
333            );
334            inc_new_counter_info!("dropped-vote-slot", 1);
335            return Err(VoteError::SlotsMismatch);
336        }
337        if slot_hashes[j].1 != vote.hash {
338            warn!(
339                "{} dropped vote {:?} failed to match hash {} {}",
340                self.node_pubkey, vote, vote.hash, slot_hashes[j].1
341            );
342            inc_new_counter_info!("dropped-vote-hash", 1);
343            return Err(VoteError::SlotHashMismatch);
344        }
345        Ok(())
346    }
347
348    pub fn process_vote(
349        &mut self,
350        vote: &Vote,
351        slot_hashes: &[SlotHash],
352        epoch: Epoch,
353    ) -> Result<(), VoteError> {
354        if vote.slots.is_empty() {
355            return Err(VoteError::EmptySlots);
356        }
357        self.check_slots_are_valid(vote, slot_hashes)?;
358
359        vote.slots
360            .iter()
361            .for_each(|s| self.process_next_vote_slot(*s, epoch));
362        Ok(())
363    }
364
365    pub fn process_next_vote_slot(&mut self, next_vote_slot: Slot, epoch: Epoch) {
366        // Ignore votes for slots earlier than we already have votes for
367        if self
368            .last_voted_slot()
369            .map_or(false, |last_voted_slot| next_vote_slot <= last_voted_slot)
370        {
371            return;
372        }
373
374        let vote = Lockout::new(next_vote_slot);
375
376        self.pop_expired_votes(next_vote_slot);
377
378        // Once the stack is full, pop the oldest lockout and distribute rewards
379        if self.votes.len() == MAX_LOCKOUT_HISTORY {
380            let vote = self.votes.pop_front().unwrap();
381            self.root_slot = Some(vote.slot);
382
383            self.increment_credits(epoch);
384        }
385        self.votes.push_back(vote);
386        self.double_lockouts();
387    }
388
389    /// increment credits, record credits for last epoch if new epoch
390    pub fn increment_credits(&mut self, epoch: Epoch) {
391        // increment credits, record by epoch
392
393        // never seen a credit
394        if self.epoch_credits.is_empty() {
395            self.epoch_credits.push((epoch, 0, 0));
396        } else if epoch != self.epoch_credits.last().unwrap().0 {
397            let (_, credits, prev_credits) = *self.epoch_credits.last().unwrap();
398
399            if credits != prev_credits {
400                // if credits were earned previous epoch
401                // append entry at end of list for the new epoch
402                self.epoch_credits.push((epoch, credits, credits));
403            } else {
404                // else just move the current epoch
405                self.epoch_credits.last_mut().unwrap().0 = epoch;
406            }
407
408            // Remove too old epoch_credits
409            if self.epoch_credits.len() > MAX_EPOCH_CREDITS_HISTORY {
410                self.epoch_credits.remove(0);
411            }
412        }
413
414        self.epoch_credits.last_mut().unwrap().1 += 1;
415    }
416
417    /// "unchecked" functions used by tests and Tower
418    pub fn process_vote_unchecked(&mut self, vote: &Vote) {
419        let slot_hashes: Vec<_> = vote.slots.iter().rev().map(|x| (*x, vote.hash)).collect();
420        let _ignored = self.process_vote(vote, &slot_hashes, self.current_epoch());
421    }
422    pub fn process_slot_vote_unchecked(&mut self, slot: Slot) {
423        self.process_vote_unchecked(&Vote::new(vec![slot], Hash::default()));
424    }
425
426    pub fn nth_recent_vote(&self, position: usize) -> Option<&Lockout> {
427        if position < self.votes.len() {
428            let pos = self.votes.len() - 1 - position;
429            self.votes.get(pos)
430        } else {
431            None
432        }
433    }
434
435    pub fn last_lockout(&self) -> Option<&Lockout> {
436        self.votes.back()
437    }
438
439    pub fn last_voted_slot(&self) -> Option<Slot> {
440        self.last_lockout().map(|v| v.slot)
441    }
442
443    // Upto MAX_LOCKOUT_HISTORY many recent unexpired
444    // vote slots pushed onto the stack.
445    pub fn tower(&self) -> Vec<Slot> {
446        self.votes.iter().map(|v| v.slot).collect()
447    }
448
449    fn current_epoch(&self) -> Epoch {
450        if self.epoch_credits.is_empty() {
451            0
452        } else {
453            self.epoch_credits.last().unwrap().0
454        }
455    }
456
457    /// Number of "credits" owed to this account from the mining pool. Submit this
458    /// VoteState to the Rewards program to trade credits for carats.
459    pub fn credits(&self) -> u64 {
460        if self.epoch_credits.is_empty() {
461            0
462        } else {
463            self.epoch_credits.last().unwrap().1
464        }
465    }
466
467    /// Number of "credits" owed to this account from the mining pool on a per-epoch basis,
468    ///  starting from credits observed.
469    /// Each tuple of (Epoch, u64, u64) is read as (epoch, credits, prev_credits), where
470    ///   credits for each epoch is credits - prev_credits; while redundant this makes
471    ///   calculating rewards over partial epochs nice and simple
472    pub fn epoch_credits(&self) -> &Vec<(Epoch, u64, u64)> {
473        &self.epoch_credits
474    }
475
476    fn set_new_authorized_voter<F>(
477        &mut self,
478        authorized_pubkey: &Pubkey,
479        current_epoch: Epoch,
480        target_epoch: Epoch,
481        verify: F,
482    ) -> Result<(), InstructionError>
483    where
484        F: Fn(Pubkey) -> Result<(), InstructionError>,
485    {
486        let epoch_authorized_voter = self.get_and_update_authorized_voter(current_epoch)?;
487        verify(epoch_authorized_voter)?;
488
489        // The offset in slots `n` on which the target_epoch
490        // (default value `DEFAULT_LEADER_SCHEDULE_SLOT_OFFSET`) is
491        // calculated is the number of slots available from the
492        // first slot `S` of an epoch in which to set a new voter for
493        // the epoch at `S` + `n`
494        if self.authorized_voters.contains(target_epoch) {
495            return Err(VoteError::TooSoonToReauthorize.into());
496        }
497
498        // Get the latest authorized_voter
499        let (latest_epoch, latest_authorized_pubkey) = self
500            .authorized_voters
501            .last()
502            .ok_or(InstructionError::InvalidAccountData)?;
503
504        // If we're not setting the same pubkey as authorized pubkey again,
505        // then update the list of prior voters to mark the expiration
506        // of the old authorized pubkey
507        if latest_authorized_pubkey != authorized_pubkey {
508            // Update the epoch ranges of authorized pubkeys that will be expired
509            let epoch_of_last_authorized_switch =
510                self.prior_voters.last().map(|range| range.2).unwrap_or(0);
511
512            // target_epoch must:
513            // 1) Be monotonically increasing due to the clock always
514            //    moving forward
515            // 2) not be equal to latest epoch otherwise this
516            //    function would have returned TooSoonToReauthorize error
517            //    above
518            assert!(target_epoch > *latest_epoch);
519
520            // Commit the new state
521            self.prior_voters.append((
522                *latest_authorized_pubkey,
523                epoch_of_last_authorized_switch,
524                target_epoch,
525            ));
526        }
527
528        self.authorized_voters
529            .insert(target_epoch, *authorized_pubkey);
530
531        Ok(())
532    }
533
534    fn get_and_update_authorized_voter(
535        &mut self,
536        current_epoch: Epoch,
537    ) -> Result<Pubkey, InstructionError> {
538        let pubkey = self
539            .authorized_voters
540            .get_and_cache_authorized_voter_for_epoch(current_epoch)
541            .ok_or(InstructionError::InvalidAccountData)?;
542        self.authorized_voters
543            .purge_authorized_voters(current_epoch);
544        Ok(pubkey)
545    }
546
547    // Pop all recent votes that are not locked out at the next vote slot.  This
548    // allows validators to switch forks once their votes for another fork have
549    // expired. This also allows validators continue voting on recent blocks in
550    // the same fork without increasing lockouts.
551    fn pop_expired_votes(&mut self, next_vote_slot: Slot) {
552        while let Some(vote) = self.last_lockout() {
553            if !vote.is_locked_out_at_slot(next_vote_slot) {
554                self.votes.pop_back();
555            } else {
556                break;
557            }
558        }
559    }
560
561    fn double_lockouts(&mut self) {
562        let stack_depth = self.votes.len();
563        for (i, v) in self.votes.iter_mut().enumerate() {
564            // Don't increase the lockout for this vote until we get more confirmations
565            // than the max number of confirmations this vote has seen
566            if stack_depth > i + v.confirmation_count as usize {
567                v.confirmation_count += 1;
568            }
569        }
570    }
571
572    pub fn process_timestamp(
573        &mut self,
574        slot: Slot,
575        timestamp: UnixTimestamp,
576    ) -> Result<(), VoteError> {
577        if (slot < self.last_timestamp.slot || timestamp < self.last_timestamp.timestamp)
578            || (slot == self.last_timestamp.slot
579                && BlockTimestamp { slot, timestamp } != self.last_timestamp
580                && self.last_timestamp.slot != 0)
581        {
582            return Err(VoteError::TimestampTooOld);
583        }
584        self.last_timestamp = BlockTimestamp { slot, timestamp };
585        Ok(())
586    }
587
588    pub fn is_uninitialized_no_deser(data: &[u8]) -> bool {
589        const VERSION_OFFSET: usize = 4;
590        data.len() != VoteState::size_of()
591            || data[VERSION_OFFSET..VERSION_OFFSET + DEFAULT_PRIOR_VOTERS_OFFSET]
592                == [0; DEFAULT_PRIOR_VOTERS_OFFSET]
593    }
594}
595
596/// Authorize the given pubkey to withdraw or sign votes. This may be called multiple times,
597/// but will implicitly withdraw authorization from the previously authorized
598/// key
599pub fn authorize<S: std::hash::BuildHasher>(
600    vote_account: &KeyedAccount,
601    authorized: &Pubkey,
602    vote_authorize: VoteAuthorize,
603    signers: &HashSet<Pubkey, S>,
604    clock: &Clock,
605) -> Result<(), InstructionError> {
606    let mut vote_state: VoteState =
607        State::<VoteStateVersions>::state(vote_account)?.convert_to_current();
608
609    // current authorized signer must say "yay"
610    match vote_authorize {
611        VoteAuthorize::Voter => {
612            vote_state.set_new_authorized_voter(
613                authorized,
614                clock.epoch,
615                clock.leader_schedule_epoch + 1,
616                |epoch_authorized_voter| verify_authorized_signer(&epoch_authorized_voter, signers),
617            )?;
618        }
619        VoteAuthorize::Withdrawer => {
620            verify_authorized_signer(&vote_state.authorized_withdrawer, signers)?;
621            vote_state.authorized_withdrawer = *authorized;
622        }
623    }
624
625    vote_account.set_state(&VoteStateVersions::new_current(vote_state))
626}
627
628/// Update the node_pubkey, requires signature of the authorized voter
629pub fn update_validator_identity<S: std::hash::BuildHasher>(
630    vote_account: &KeyedAccount,
631    node_pubkey: &Pubkey,
632    signers: &HashSet<Pubkey, S>,
633) -> Result<(), InstructionError> {
634    let mut vote_state: VoteState =
635        State::<VoteStateVersions>::state(vote_account)?.convert_to_current();
636
637    // current authorized withdrawer must say "yay"
638    verify_authorized_signer(&vote_state.authorized_withdrawer, signers)?;
639
640    // new node must say "yay"
641    verify_authorized_signer(node_pubkey, signers)?;
642
643    vote_state.node_pubkey = *node_pubkey;
644
645    vote_account.set_state(&VoteStateVersions::new_current(vote_state))
646}
647
648/// Update the vote account's commission
649pub fn update_commission<S: std::hash::BuildHasher>(
650    vote_account: &KeyedAccount,
651    commission: u8,
652    signers: &HashSet<Pubkey, S>,
653) -> Result<(), InstructionError> {
654    let mut vote_state: VoteState =
655        State::<VoteStateVersions>::state(vote_account)?.convert_to_current();
656
657    // current authorized withdrawer must say "yay"
658    verify_authorized_signer(&vote_state.authorized_withdrawer, signers)?;
659
660    vote_state.commission = commission;
661
662    vote_account.set_state(&VoteStateVersions::new_current(vote_state))
663}
664
665fn verify_authorized_signer<S: std::hash::BuildHasher>(
666    authorized: &Pubkey,
667    signers: &HashSet<Pubkey, S>,
668) -> Result<(), InstructionError> {
669    if signers.contains(authorized) {
670        Ok(())
671    } else {
672        Err(InstructionError::MissingRequiredSignature)
673    }
674}
675
676/// Withdraw funds from the vote account
677pub fn withdraw<S: std::hash::BuildHasher>(
678    vote_account: &KeyedAccount,
679    carats: u64,
680    to_account: &KeyedAccount,
681    signers: &HashSet<Pubkey, S>,
682) -> Result<(), InstructionError> {
683    let vote_state: VoteState =
684        State::<VoteStateVersions>::state(vote_account)?.convert_to_current();
685
686    verify_authorized_signer(&vote_state.authorized_withdrawer, signers)?;
687
688    match vote_account.carats()?.cmp(&carats) {
689        Ordering::Less => return Err(InstructionError::InsufficientFunds),
690        Ordering::Equal => {
691            // Deinitialize upon zero-balance
692            vote_account.set_state(&VoteStateVersions::new_current(VoteState::default()))?;
693        }
694        _ => (),
695    }
696    vote_account
697        .try_account_ref_mut()?
698        .checked_sub_carats(carats)?;
699    to_account
700        .try_account_ref_mut()?
701        .checked_add_carats(carats)?;
702    Ok(())
703}
704
705/// Initialize the vote_state for a vote account
706/// Assumes that the account is being init as part of a account creation or balance transfer and
707/// that the transaction must be signed by the staker's keys
708pub fn initialize_account<S: std::hash::BuildHasher>(
709    vote_account: &KeyedAccount,
710    vote_init: &VoteInit,
711    signers: &HashSet<Pubkey, S>,
712    clock: &Clock,
713    check_data_size: bool,
714) -> Result<(), InstructionError> {
715    if check_data_size && vote_account.data_len()? != VoteState::size_of() {
716        return Err(InstructionError::InvalidAccountData);
717    }
718    let versioned = State::<VoteStateVersions>::state(vote_account)?;
719
720    if !versioned.is_uninitialized() {
721        return Err(InstructionError::AccountAlreadyInitialized);
722    }
723
724    // node must agree to accept this vote account
725    verify_authorized_signer(&vote_init.node_pubkey, signers)?;
726
727    vote_account.set_state(&VoteStateVersions::new_current(VoteState::new(
728        vote_init, clock,
729    )))
730}
731
732pub fn process_vote<S: std::hash::BuildHasher>(
733    vote_account: &KeyedAccount,
734    slot_hashes: &[SlotHash],
735    clock: &Clock,
736    vote: &Vote,
737    signers: &HashSet<Pubkey, S>,
738) -> Result<(), InstructionError> {
739    let versioned = State::<VoteStateVersions>::state(vote_account)?;
740
741    if versioned.is_uninitialized() {
742        return Err(InstructionError::UninitializedAccount);
743    }
744
745    let mut vote_state = versioned.convert_to_current();
746    let authorized_voter = vote_state.get_and_update_authorized_voter(clock.epoch)?;
747    verify_authorized_signer(&authorized_voter, signers)?;
748
749    vote_state.process_vote(vote, slot_hashes, clock.epoch)?;
750    if let Some(timestamp) = vote.timestamp {
751        vote.slots
752            .iter()
753            .max()
754            .ok_or(VoteError::EmptySlots)
755            .and_then(|slot| vote_state.process_timestamp(*slot, timestamp))?;
756    }
757    vote_account.set_state(&VoteStateVersions::new_current(vote_state))
758}
759
760pub fn create_account_with_authorized(
761    node_pubkey: &Pubkey,
762    authorized_voter: &Pubkey,
763    authorized_withdrawer: &Pubkey,
764    commission: u8,
765    carats: u64,
766) -> AccountSharedData {
767    let mut vote_account = AccountSharedData::new(carats, VoteState::size_of(), &id());
768
769    let vote_state = VoteState::new(
770        &VoteInit {
771            node_pubkey: *node_pubkey,
772            authorized_voter: *authorized_voter,
773            authorized_withdrawer: *authorized_withdrawer,
774            commission,
775        },
776        &Clock::default(),
777    );
778
779    let versioned = VoteStateVersions::new_current(vote_state);
780    VoteState::to(&versioned, &mut vote_account).unwrap();
781
782    vote_account
783}
784
785// create_account() should be removed, use create_account_with_authorized() instead
786pub fn create_account(
787    vote_pubkey: &Pubkey,
788    node_pubkey: &Pubkey,
789    commission: u8,
790    carats: u64,
791) -> AccountSharedData {
792    create_account_with_authorized(node_pubkey, vote_pubkey, vote_pubkey, commission, carats)
793}
794
795#[cfg(test)]
796mod tests {
797    use super::*;
798    use crate::vote_state;
799    use gemachain_sdk::{
800        account::AccountSharedData,
801        account_utils::StateMut,
802        hash::hash,
803        keyed_account::{get_signers, keyed_account_at_index},
804    };
805    use std::cell::RefCell;
806
807    const MAX_RECENT_VOTES: usize = 16;
808
809    impl VoteState {
810        pub fn new_for_test(auth_pubkey: &Pubkey) -> Self {
811            Self::new(
812                &VoteInit {
813                    node_pubkey: gemachain_sdk::pubkey::new_rand(),
814                    authorized_voter: *auth_pubkey,
815                    authorized_withdrawer: *auth_pubkey,
816                    commission: 0,
817                },
818                &Clock::default(),
819            )
820        }
821    }
822
823    #[test]
824    fn test_initialize_vote_account() {
825        let vote_account_pubkey = gemachain_sdk::pubkey::new_rand();
826        let vote_account = AccountSharedData::new_ref(100, VoteState::size_of(), &id());
827        let vote_account = KeyedAccount::new(&vote_account_pubkey, false, &vote_account);
828
829        let node_pubkey = gemachain_sdk::pubkey::new_rand();
830        let node_account = RefCell::new(AccountSharedData::default());
831        let keyed_accounts = &[];
832        let signers: HashSet<Pubkey> = get_signers(keyed_accounts);
833
834        //init should fail, node_pubkey didn't sign the transaction
835        let res = initialize_account(
836            &vote_account,
837            &VoteInit {
838                node_pubkey,
839                authorized_voter: vote_account_pubkey,
840                authorized_withdrawer: vote_account_pubkey,
841                commission: 0,
842            },
843            &signers,
844            &Clock::default(),
845            true,
846        );
847        assert_eq!(res, Err(InstructionError::MissingRequiredSignature));
848
849        let keyed_accounts = &[KeyedAccount::new(&node_pubkey, true, &node_account)];
850        let signers: HashSet<Pubkey> = get_signers(keyed_accounts);
851
852        //init should pass
853        let res = initialize_account(
854            &vote_account,
855            &VoteInit {
856                node_pubkey,
857                authorized_voter: vote_account_pubkey,
858                authorized_withdrawer: vote_account_pubkey,
859                commission: 0,
860            },
861            &signers,
862            &Clock::default(),
863            true,
864        );
865        assert_eq!(res, Ok(()));
866
867        // reinit should fail
868        let res = initialize_account(
869            &vote_account,
870            &VoteInit {
871                node_pubkey,
872                authorized_voter: vote_account_pubkey,
873                authorized_withdrawer: vote_account_pubkey,
874                commission: 0,
875            },
876            &signers,
877            &Clock::default(),
878            true,
879        );
880        assert_eq!(res, Err(InstructionError::AccountAlreadyInitialized));
881
882        //init should fail, account is too big
883        let large_vote_account = AccountSharedData::new_ref(100, 2 * VoteState::size_of(), &id());
884        let large_vote_account =
885            KeyedAccount::new(&vote_account_pubkey, false, &large_vote_account);
886        let res = initialize_account(
887            &large_vote_account,
888            &VoteInit {
889                node_pubkey,
890                authorized_voter: vote_account_pubkey,
891                authorized_withdrawer: vote_account_pubkey,
892                commission: 0,
893            },
894            &signers,
895            &Clock::default(),
896            true,
897        );
898        assert_eq!(res, Err(InstructionError::InvalidAccountData));
899    }
900
901    fn create_test_account() -> (Pubkey, RefCell<AccountSharedData>) {
902        let vote_pubkey = gemachain_sdk::pubkey::new_rand();
903        (
904            vote_pubkey,
905            RefCell::new(vote_state::create_account(
906                &vote_pubkey,
907                &gemachain_sdk::pubkey::new_rand(),
908                0,
909                100,
910            )),
911        )
912    }
913
914    fn create_test_account_with_authorized() -> (Pubkey, Pubkey, Pubkey, RefCell<AccountSharedData>)
915    {
916        let vote_pubkey = gemachain_sdk::pubkey::new_rand();
917        let authorized_voter = gemachain_sdk::pubkey::new_rand();
918        let authorized_withdrawer = gemachain_sdk::pubkey::new_rand();
919
920        (
921            vote_pubkey,
922            authorized_voter,
923            authorized_withdrawer,
924            RefCell::new(vote_state::create_account_with_authorized(
925                &gemachain_sdk::pubkey::new_rand(),
926                &authorized_voter,
927                &authorized_withdrawer,
928                0,
929                100,
930            )),
931        )
932    }
933
934    fn simulate_process_vote(
935        vote_pubkey: &Pubkey,
936        vote_account: &RefCell<AccountSharedData>,
937        vote: &Vote,
938        slot_hashes: &[SlotHash],
939        epoch: Epoch,
940    ) -> Result<VoteState, InstructionError> {
941        let keyed_accounts = &[KeyedAccount::new(vote_pubkey, true, vote_account)];
942        let signers: HashSet<Pubkey> = get_signers(keyed_accounts);
943        process_vote(
944            &keyed_accounts[0],
945            slot_hashes,
946            &Clock {
947                epoch,
948                ..Clock::default()
949            },
950            &vote.clone(),
951            &signers,
952        )?;
953        StateMut::<VoteStateVersions>::state(&*vote_account.borrow())
954            .map(|versioned| versioned.convert_to_current())
955    }
956
957    /// exercises all the keyed accounts stuff
958    fn simulate_process_vote_unchecked(
959        vote_pubkey: &Pubkey,
960        vote_account: &RefCell<AccountSharedData>,
961        vote: &Vote,
962    ) -> Result<VoteState, InstructionError> {
963        simulate_process_vote(
964            vote_pubkey,
965            vote_account,
966            vote,
967            &[(*vote.slots.last().unwrap(), vote.hash)],
968            0,
969        )
970    }
971
972    #[test]
973    fn test_vote_serialize() {
974        let mut buffer: Vec<u8> = vec![0; VoteState::size_of()];
975        let mut vote_state = VoteState::default();
976        vote_state
977            .votes
978            .resize(MAX_LOCKOUT_HISTORY, Lockout::default());
979        let versioned = VoteStateVersions::new_current(vote_state);
980        assert!(VoteState::serialize(&versioned, &mut buffer[0..4]).is_err());
981        VoteState::serialize(&versioned, &mut buffer).unwrap();
982        assert_eq!(
983            VoteStateVersions::new_current(VoteState::deserialize(&buffer).unwrap()),
984            versioned
985        );
986    }
987
988    #[test]
989    fn test_voter_registration() {
990        let (vote_pubkey, vote_account) = create_test_account();
991
992        let vote_state: VoteState = StateMut::<VoteStateVersions>::state(&*vote_account.borrow())
993            .unwrap()
994            .convert_to_current();
995        assert_eq!(vote_state.authorized_voters.len(), 1);
996        assert_eq!(
997            *vote_state.authorized_voters.first().unwrap().1,
998            vote_pubkey
999        );
1000        assert!(vote_state.votes.is_empty());
1001    }
1002
1003    #[test]
1004    fn test_vote() {
1005        let (vote_pubkey, vote_account) = create_test_account();
1006
1007        let vote = Vote::new(vec![1], Hash::default());
1008        let vote_state =
1009            simulate_process_vote_unchecked(&vote_pubkey, &vote_account, &vote).unwrap();
1010        assert_eq!(
1011            vote_state.votes,
1012            vec![Lockout::new(*vote.slots.last().unwrap())]
1013        );
1014        assert_eq!(vote_state.credits(), 0);
1015    }
1016
1017    #[test]
1018    fn test_vote_slot_hashes() {
1019        let (vote_pubkey, vote_account) = create_test_account();
1020
1021        let hash = hash(&[0u8]);
1022        let vote = Vote::new(vec![0], hash);
1023
1024        // wrong hash
1025        assert_eq!(
1026            simulate_process_vote(
1027                &vote_pubkey,
1028                &vote_account,
1029                &vote,
1030                &[(0, Hash::default())],
1031                0,
1032            ),
1033            Err(VoteError::SlotHashMismatch.into())
1034        );
1035
1036        // wrong slot
1037        assert_eq!(
1038            simulate_process_vote(&vote_pubkey, &vote_account, &vote, &[(1, hash)], 0),
1039            Err(VoteError::SlotsMismatch.into())
1040        );
1041
1042        // empty slot_hashes
1043        assert_eq!(
1044            simulate_process_vote(&vote_pubkey, &vote_account, &vote, &[], 0),
1045            Err(VoteError::VoteTooOld.into())
1046        );
1047    }
1048
1049    #[test]
1050    fn test_vote_update_validator_identity() {
1051        let (vote_pubkey, _authorized_voter, authorized_withdrawer, vote_account) =
1052            create_test_account_with_authorized();
1053
1054        let node_pubkey = gemachain_sdk::pubkey::new_rand();
1055        let node_account = RefCell::new(AccountSharedData::default());
1056        let authorized_withdrawer_account = RefCell::new(AccountSharedData::default());
1057
1058        let keyed_accounts = &[
1059            KeyedAccount::new(&vote_pubkey, true, &vote_account),
1060            KeyedAccount::new(&node_pubkey, false, &node_account),
1061            KeyedAccount::new(&authorized_withdrawer, true, &authorized_withdrawer_account),
1062        ];
1063        let signers: HashSet<Pubkey> = get_signers(keyed_accounts);
1064        let res = update_validator_identity(&keyed_accounts[0], &node_pubkey, &signers);
1065        assert_eq!(res, Err(InstructionError::MissingRequiredSignature));
1066
1067        let keyed_accounts = &[
1068            KeyedAccount::new(&vote_pubkey, true, &vote_account),
1069            KeyedAccount::new(&node_pubkey, true, &node_account),
1070            KeyedAccount::new(
1071                &authorized_withdrawer,
1072                false,
1073                &authorized_withdrawer_account,
1074            ),
1075        ];
1076        let signers: HashSet<Pubkey> = get_signers(keyed_accounts);
1077        let res = update_validator_identity(&keyed_accounts[0], &node_pubkey, &signers);
1078        assert_eq!(res, Err(InstructionError::MissingRequiredSignature));
1079        let vote_state: VoteState = StateMut::<VoteStateVersions>::state(&*vote_account.borrow())
1080            .unwrap()
1081            .convert_to_current();
1082        assert!(vote_state.node_pubkey != node_pubkey);
1083
1084        let keyed_accounts = &[
1085            KeyedAccount::new(&vote_pubkey, true, &vote_account),
1086            KeyedAccount::new(&node_pubkey, true, &node_account),
1087            KeyedAccount::new(&authorized_withdrawer, true, &authorized_withdrawer_account),
1088        ];
1089        let signers: HashSet<Pubkey> = get_signers(keyed_accounts);
1090        let res = update_validator_identity(&keyed_accounts[0], &node_pubkey, &signers);
1091        assert_eq!(res, Ok(()));
1092        let vote_state: VoteState = StateMut::<VoteStateVersions>::state(&*vote_account.borrow())
1093            .unwrap()
1094            .convert_to_current();
1095        assert_eq!(vote_state.node_pubkey, node_pubkey);
1096    }
1097
1098    #[test]
1099    fn test_vote_update_commission() {
1100        let (vote_pubkey, _authorized_voter, authorized_withdrawer, vote_account) =
1101            create_test_account_with_authorized();
1102
1103        let authorized_withdrawer_account = RefCell::new(AccountSharedData::default());
1104
1105        let keyed_accounts = &[
1106            KeyedAccount::new(&vote_pubkey, true, &vote_account),
1107            KeyedAccount::new(
1108                &authorized_withdrawer,
1109                false,
1110                &authorized_withdrawer_account,
1111            ),
1112        ];
1113        let signers: HashSet<Pubkey> = get_signers(keyed_accounts);
1114        let res = update_commission(&keyed_accounts[0], 42, &signers);
1115        assert_eq!(res, Err(InstructionError::MissingRequiredSignature));
1116
1117        let keyed_accounts = &[
1118            KeyedAccount::new(&vote_pubkey, true, &vote_account),
1119            KeyedAccount::new(&authorized_withdrawer, true, &authorized_withdrawer_account),
1120        ];
1121        let signers: HashSet<Pubkey> = get_signers(keyed_accounts);
1122        let res = update_commission(&keyed_accounts[0], 42, &signers);
1123        assert_eq!(res, Ok(()));
1124        let vote_state: VoteState = StateMut::<VoteStateVersions>::state(&*vote_account.borrow())
1125            .unwrap()
1126            .convert_to_current();
1127        assert_eq!(vote_state.commission, 42);
1128
1129        let keyed_accounts = &[
1130            KeyedAccount::new(&vote_pubkey, true, &vote_account),
1131            KeyedAccount::new(&authorized_withdrawer, true, &authorized_withdrawer_account),
1132        ];
1133        let signers: HashSet<Pubkey> = get_signers(keyed_accounts);
1134        let res = update_commission(&keyed_accounts[0], u8::MAX, &signers);
1135        assert_eq!(res, Ok(()));
1136        let vote_state: VoteState = StateMut::<VoteStateVersions>::state(&*vote_account.borrow())
1137            .unwrap()
1138            .convert_to_current();
1139        assert_eq!(vote_state.commission, u8::MAX);
1140    }
1141
1142    #[test]
1143    fn test_vote_signature() {
1144        let (vote_pubkey, vote_account) = create_test_account();
1145        let vote = Vote::new(vec![1], Hash::default());
1146
1147        // unsigned
1148        let keyed_accounts = &[KeyedAccount::new(&vote_pubkey, false, &vote_account)];
1149        let signers: HashSet<Pubkey> = get_signers(keyed_accounts);
1150        let res = process_vote(
1151            &keyed_accounts[0],
1152            &[(*vote.slots.last().unwrap(), vote.hash)],
1153            &Clock {
1154                epoch: 1,
1155                leader_schedule_epoch: 2,
1156                ..Clock::default()
1157            },
1158            &vote,
1159            &signers,
1160        );
1161        assert_eq!(res, Err(InstructionError::MissingRequiredSignature));
1162
1163        // signed
1164        let keyed_accounts = &[KeyedAccount::new(&vote_pubkey, true, &vote_account)];
1165        let signers: HashSet<Pubkey> = get_signers(keyed_accounts);
1166        let res = process_vote(
1167            &keyed_accounts[0],
1168            &[(*vote.slots.last().unwrap(), vote.hash)],
1169            &Clock {
1170                epoch: 1,
1171                leader_schedule_epoch: 2,
1172                ..Clock::default()
1173            },
1174            &vote,
1175            &signers,
1176        );
1177        assert_eq!(res, Ok(()));
1178
1179        // another voter, unsigned
1180        let keyed_accounts = &[KeyedAccount::new(&vote_pubkey, false, &vote_account)];
1181        let signers: HashSet<Pubkey> = get_signers(keyed_accounts);
1182        let authorized_voter_pubkey = gemachain_sdk::pubkey::new_rand();
1183        let res = authorize(
1184            &keyed_accounts[0],
1185            &authorized_voter_pubkey,
1186            VoteAuthorize::Voter,
1187            &signers,
1188            &Clock {
1189                epoch: 1,
1190                leader_schedule_epoch: 2,
1191                ..Clock::default()
1192            },
1193        );
1194        assert_eq!(res, Err(InstructionError::MissingRequiredSignature));
1195
1196        let keyed_accounts = &[KeyedAccount::new(&vote_pubkey, true, &vote_account)];
1197        let signers: HashSet<Pubkey> = get_signers(keyed_accounts);
1198        let res = authorize(
1199            &keyed_accounts[0],
1200            &authorized_voter_pubkey,
1201            VoteAuthorize::Voter,
1202            &signers,
1203            &Clock {
1204                epoch: 1,
1205                leader_schedule_epoch: 2,
1206                ..Clock::default()
1207            },
1208        );
1209        assert_eq!(res, Ok(()));
1210
1211        // Already set an authorized voter earlier for leader_schedule_epoch == 2
1212        let signers: HashSet<Pubkey> = get_signers(keyed_accounts);
1213        let res = authorize(
1214            &keyed_accounts[0],
1215            &authorized_voter_pubkey,
1216            VoteAuthorize::Voter,
1217            &signers,
1218            &Clock {
1219                epoch: 1,
1220                leader_schedule_epoch: 2,
1221                ..Clock::default()
1222            },
1223        );
1224        assert_eq!(res, Err(VoteError::TooSoonToReauthorize.into()));
1225
1226        // verify authorized_voter_pubkey can authorize authorized_voter_pubkey ;)
1227        let authorized_voter_account = RefCell::new(AccountSharedData::default());
1228        let keyed_accounts = &[
1229            KeyedAccount::new(&vote_pubkey, false, &vote_account),
1230            KeyedAccount::new(&authorized_voter_pubkey, true, &authorized_voter_account),
1231        ];
1232        let signers: HashSet<Pubkey> = get_signers(keyed_accounts);
1233        let res = authorize(
1234            &keyed_accounts[0],
1235            &authorized_voter_pubkey,
1236            VoteAuthorize::Voter,
1237            &signers,
1238            &Clock {
1239                // The authorized voter was set when leader_schedule_epoch == 2, so will
1240                // take effect when epoch == 3
1241                epoch: 3,
1242                leader_schedule_epoch: 4,
1243                ..Clock::default()
1244            },
1245        );
1246        assert_eq!(res, Ok(()));
1247
1248        // authorize another withdrawer
1249        // another voter
1250        let keyed_accounts = &[KeyedAccount::new(&vote_pubkey, true, &vote_account)];
1251        let signers: HashSet<Pubkey> = get_signers(keyed_accounts);
1252        let authorized_withdrawer_pubkey = gemachain_sdk::pubkey::new_rand();
1253        let res = authorize(
1254            &keyed_accounts[0],
1255            &authorized_withdrawer_pubkey,
1256            VoteAuthorize::Withdrawer,
1257            &signers,
1258            &Clock {
1259                epoch: 3,
1260                leader_schedule_epoch: 4,
1261                ..Clock::default()
1262            },
1263        );
1264        assert_eq!(res, Ok(()));
1265
1266        // verify authorized_withdrawer can authorize authorized_withdrawer ;)
1267        let withdrawer_account = RefCell::new(AccountSharedData::default());
1268        let keyed_accounts = &[
1269            KeyedAccount::new(&vote_pubkey, false, &vote_account),
1270            KeyedAccount::new(&authorized_withdrawer_pubkey, true, &withdrawer_account),
1271        ];
1272        let signers: HashSet<Pubkey> = get_signers(keyed_accounts);
1273        let res = authorize(
1274            &keyed_accounts[0],
1275            &authorized_withdrawer_pubkey,
1276            VoteAuthorize::Withdrawer,
1277            &signers,
1278            &Clock {
1279                epoch: 3,
1280                leader_schedule_epoch: 4,
1281                ..Clock::default()
1282            },
1283        );
1284        assert_eq!(res, Ok(()));
1285
1286        // not signed by authorized voter
1287        let keyed_accounts = &[KeyedAccount::new(&vote_pubkey, true, &vote_account)];
1288        let signers: HashSet<Pubkey> = get_signers(keyed_accounts);
1289        let vote = Vote::new(vec![2], Hash::default());
1290        let res = process_vote(
1291            &keyed_accounts[0],
1292            &[(*vote.slots.last().unwrap(), vote.hash)],
1293            &Clock {
1294                epoch: 3,
1295                leader_schedule_epoch: 4,
1296                ..Clock::default()
1297            },
1298            &vote,
1299            &signers,
1300        );
1301        assert_eq!(res, Err(InstructionError::MissingRequiredSignature));
1302
1303        // signed by authorized voter
1304        let authorized_voter_account = RefCell::new(AccountSharedData::default());
1305        let keyed_accounts = &[
1306            KeyedAccount::new(&vote_pubkey, false, &vote_account),
1307            KeyedAccount::new(&authorized_voter_pubkey, true, &authorized_voter_account),
1308        ];
1309        let signers: HashSet<Pubkey> = get_signers(keyed_accounts);
1310        let vote = Vote::new(vec![2], Hash::default());
1311        let res = process_vote(
1312            &keyed_accounts[0],
1313            &[(*vote.slots.last().unwrap(), vote.hash)],
1314            &Clock {
1315                epoch: 3,
1316                leader_schedule_epoch: 4,
1317                ..Clock::default()
1318            },
1319            &vote,
1320            &signers,
1321        );
1322        assert_eq!(res, Ok(()));
1323    }
1324
1325    #[test]
1326    fn test_vote_without_initialization() {
1327        let vote_pubkey = gemachain_sdk::pubkey::new_rand();
1328        let vote_account = RefCell::new(AccountSharedData::new(100, VoteState::size_of(), &id()));
1329
1330        let res = simulate_process_vote_unchecked(
1331            &vote_pubkey,
1332            &vote_account,
1333            &Vote::new(vec![1], Hash::default()),
1334        );
1335        assert_eq!(res, Err(InstructionError::UninitializedAccount));
1336    }
1337
1338    #[test]
1339    fn test_vote_lockout() {
1340        let (_vote_pubkey, vote_account) = create_test_account();
1341
1342        let mut vote_state: VoteState =
1343            StateMut::<VoteStateVersions>::state(&*vote_account.borrow())
1344                .unwrap()
1345                .convert_to_current();
1346
1347        for i in 0..(MAX_LOCKOUT_HISTORY + 1) {
1348            vote_state.process_slot_vote_unchecked((INITIAL_LOCKOUT as usize * i) as u64);
1349        }
1350
1351        // The last vote should have been popped b/c it reached a depth of MAX_LOCKOUT_HISTORY
1352        assert_eq!(vote_state.votes.len(), MAX_LOCKOUT_HISTORY);
1353        assert_eq!(vote_state.root_slot, Some(0));
1354        check_lockouts(&vote_state);
1355
1356        // One more vote that confirms the entire stack,
1357        // the root_slot should change to the
1358        // second vote
1359        let top_vote = vote_state.votes.front().unwrap().slot;
1360        vote_state
1361            .process_slot_vote_unchecked(vote_state.last_lockout().unwrap().last_locked_out_slot());
1362        assert_eq!(Some(top_vote), vote_state.root_slot);
1363
1364        // Expire everything except the first vote
1365        vote_state
1366            .process_slot_vote_unchecked(vote_state.votes.front().unwrap().last_locked_out_slot());
1367        // First vote and new vote are both stored for a total of 2 votes
1368        assert_eq!(vote_state.votes.len(), 2);
1369    }
1370
1371    #[test]
1372    fn test_vote_double_lockout_after_expiration() {
1373        let voter_pubkey = gemachain_sdk::pubkey::new_rand();
1374        let mut vote_state = VoteState::new_for_test(&voter_pubkey);
1375
1376        for i in 0..3 {
1377            vote_state.process_slot_vote_unchecked(i as u64);
1378        }
1379
1380        check_lockouts(&vote_state);
1381
1382        // Expire the third vote (which was a vote for slot 2). The height of the
1383        // vote stack is unchanged, so none of the previous votes should have
1384        // doubled in lockout
1385        vote_state.process_slot_vote_unchecked((2 + INITIAL_LOCKOUT + 1) as u64);
1386        check_lockouts(&vote_state);
1387
1388        // Vote again, this time the vote stack depth increases, so the votes should
1389        // double for everybody
1390        vote_state.process_slot_vote_unchecked((2 + INITIAL_LOCKOUT + 2) as u64);
1391        check_lockouts(&vote_state);
1392
1393        // Vote again, this time the vote stack depth increases, so the votes should
1394        // double for everybody
1395        vote_state.process_slot_vote_unchecked((2 + INITIAL_LOCKOUT + 3) as u64);
1396        check_lockouts(&vote_state);
1397    }
1398
1399    #[test]
1400    fn test_expire_multiple_votes() {
1401        let voter_pubkey = gemachain_sdk::pubkey::new_rand();
1402        let mut vote_state = VoteState::new_for_test(&voter_pubkey);
1403
1404        for i in 0..3 {
1405            vote_state.process_slot_vote_unchecked(i as u64);
1406        }
1407
1408        assert_eq!(vote_state.votes[0].confirmation_count, 3);
1409
1410        // Expire the second and third votes
1411        let expire_slot = vote_state.votes[1].slot + vote_state.votes[1].lockout() + 1;
1412        vote_state.process_slot_vote_unchecked(expire_slot);
1413        assert_eq!(vote_state.votes.len(), 2);
1414
1415        // Check that the old votes expired
1416        assert_eq!(vote_state.votes[0].slot, 0);
1417        assert_eq!(vote_state.votes[1].slot, expire_slot);
1418
1419        // Process one more vote
1420        vote_state.process_slot_vote_unchecked(expire_slot + 1);
1421
1422        // Confirmation count for the older first vote should remain unchanged
1423        assert_eq!(vote_state.votes[0].confirmation_count, 3);
1424
1425        // The later votes should still have increasing confirmation counts
1426        assert_eq!(vote_state.votes[1].confirmation_count, 2);
1427        assert_eq!(vote_state.votes[2].confirmation_count, 1);
1428    }
1429
1430    #[test]
1431    fn test_vote_credits() {
1432        let voter_pubkey = gemachain_sdk::pubkey::new_rand();
1433        let mut vote_state = VoteState::new_for_test(&voter_pubkey);
1434
1435        for i in 0..MAX_LOCKOUT_HISTORY {
1436            vote_state.process_slot_vote_unchecked(i as u64);
1437        }
1438
1439        assert_eq!(vote_state.credits(), 0);
1440
1441        vote_state.process_slot_vote_unchecked(MAX_LOCKOUT_HISTORY as u64 + 1);
1442        assert_eq!(vote_state.credits(), 1);
1443        vote_state.process_slot_vote_unchecked(MAX_LOCKOUT_HISTORY as u64 + 2);
1444        assert_eq!(vote_state.credits(), 2);
1445        vote_state.process_slot_vote_unchecked(MAX_LOCKOUT_HISTORY as u64 + 3);
1446        assert_eq!(vote_state.credits(), 3);
1447    }
1448
1449    #[test]
1450    fn test_duplicate_vote() {
1451        let voter_pubkey = gemachain_sdk::pubkey::new_rand();
1452        let mut vote_state = VoteState::new_for_test(&voter_pubkey);
1453        vote_state.process_slot_vote_unchecked(0);
1454        vote_state.process_slot_vote_unchecked(1);
1455        vote_state.process_slot_vote_unchecked(0);
1456        assert_eq!(vote_state.nth_recent_vote(0).unwrap().slot, 1);
1457        assert_eq!(vote_state.nth_recent_vote(1).unwrap().slot, 0);
1458        assert!(vote_state.nth_recent_vote(2).is_none());
1459    }
1460
1461    #[test]
1462    fn test_nth_recent_vote() {
1463        let voter_pubkey = gemachain_sdk::pubkey::new_rand();
1464        let mut vote_state = VoteState::new_for_test(&voter_pubkey);
1465        for i in 0..MAX_LOCKOUT_HISTORY {
1466            vote_state.process_slot_vote_unchecked(i as u64);
1467        }
1468        for i in 0..(MAX_LOCKOUT_HISTORY - 1) {
1469            assert_eq!(
1470                vote_state.nth_recent_vote(i).unwrap().slot as usize,
1471                MAX_LOCKOUT_HISTORY - i - 1,
1472            );
1473        }
1474        assert!(vote_state.nth_recent_vote(MAX_LOCKOUT_HISTORY).is_none());
1475    }
1476
1477    fn check_lockouts(vote_state: &VoteState) {
1478        for (i, vote) in vote_state.votes.iter().enumerate() {
1479            let num_votes = vote_state.votes.len() - i;
1480            assert_eq!(vote.lockout(), INITIAL_LOCKOUT.pow(num_votes as u32) as u64);
1481        }
1482    }
1483
1484    fn recent_votes(vote_state: &VoteState) -> Vec<Vote> {
1485        let start = vote_state.votes.len().saturating_sub(MAX_RECENT_VOTES);
1486        (start..vote_state.votes.len())
1487            .map(|i| Vote::new(vec![vote_state.votes.get(i).unwrap().slot], Hash::default()))
1488            .collect()
1489    }
1490
1491    /// check that two accounts with different data can be brought to the same state with one vote submission
1492    #[test]
1493    fn test_process_missed_votes() {
1494        let account_a = gemachain_sdk::pubkey::new_rand();
1495        let mut vote_state_a = VoteState::new_for_test(&account_a);
1496        let account_b = gemachain_sdk::pubkey::new_rand();
1497        let mut vote_state_b = VoteState::new_for_test(&account_b);
1498
1499        // process some votes on account a
1500        (0..5).for_each(|i| vote_state_a.process_slot_vote_unchecked(i as u64));
1501        assert_ne!(recent_votes(&vote_state_a), recent_votes(&vote_state_b));
1502
1503        // as long as b has missed less than "NUM_RECENT" votes both accounts should be in sync
1504        let slots = (0u64..MAX_RECENT_VOTES as u64).collect();
1505        let vote = Vote::new(slots, Hash::default());
1506        let slot_hashes: Vec<_> = vote.slots.iter().rev().map(|x| (*x, vote.hash)).collect();
1507
1508        assert_eq!(vote_state_a.process_vote(&vote, &slot_hashes, 0), Ok(()));
1509        assert_eq!(vote_state_b.process_vote(&vote, &slot_hashes, 0), Ok(()));
1510        assert_eq!(recent_votes(&vote_state_a), recent_votes(&vote_state_b));
1511    }
1512
1513    #[test]
1514    fn test_process_vote_skips_old_vote() {
1515        let mut vote_state = VoteState::default();
1516
1517        let vote = Vote::new(vec![0], Hash::default());
1518        let slot_hashes: Vec<_> = vec![(0, vote.hash)];
1519        assert_eq!(vote_state.process_vote(&vote, &slot_hashes, 0), Ok(()));
1520        let recent = recent_votes(&vote_state);
1521        assert_eq!(
1522            vote_state.process_vote(&vote, &slot_hashes, 0),
1523            Err(VoteError::VoteTooOld)
1524        );
1525        assert_eq!(recent, recent_votes(&vote_state));
1526    }
1527
1528    #[test]
1529    fn test_check_slots_are_valid_vote_empty_slot_hashes() {
1530        let vote_state = VoteState::default();
1531
1532        let vote = Vote::new(vec![0], Hash::default());
1533        assert_eq!(
1534            vote_state.check_slots_are_valid(&vote, &[]),
1535            Err(VoteError::VoteTooOld)
1536        );
1537    }
1538
1539    #[test]
1540    fn test_check_slots_are_valid_new_vote() {
1541        let vote_state = VoteState::default();
1542
1543        let vote = Vote::new(vec![0], Hash::default());
1544        let slot_hashes: Vec<_> = vec![(*vote.slots.last().unwrap(), vote.hash)];
1545        assert_eq!(
1546            vote_state.check_slots_are_valid(&vote, &slot_hashes),
1547            Ok(())
1548        );
1549    }
1550
1551    #[test]
1552    fn test_check_slots_are_valid_bad_hash() {
1553        let vote_state = VoteState::default();
1554
1555        let vote = Vote::new(vec![0], Hash::default());
1556        let slot_hashes: Vec<_> = vec![(*vote.slots.last().unwrap(), hash(vote.hash.as_ref()))];
1557        assert_eq!(
1558            vote_state.check_slots_are_valid(&vote, &slot_hashes),
1559            Err(VoteError::SlotHashMismatch)
1560        );
1561    }
1562
1563    #[test]
1564    fn test_check_slots_are_valid_bad_slot() {
1565        let vote_state = VoteState::default();
1566
1567        let vote = Vote::new(vec![1], Hash::default());
1568        let slot_hashes: Vec<_> = vec![(0, vote.hash)];
1569        assert_eq!(
1570            vote_state.check_slots_are_valid(&vote, &slot_hashes),
1571            Err(VoteError::SlotsMismatch)
1572        );
1573    }
1574
1575    #[test]
1576    fn test_check_slots_are_valid_duplicate_vote() {
1577        let mut vote_state = VoteState::default();
1578
1579        let vote = Vote::new(vec![0], Hash::default());
1580        let slot_hashes: Vec<_> = vec![(*vote.slots.last().unwrap(), vote.hash)];
1581        assert_eq!(vote_state.process_vote(&vote, &slot_hashes, 0), Ok(()));
1582        assert_eq!(
1583            vote_state.check_slots_are_valid(&vote, &slot_hashes),
1584            Err(VoteError::VoteTooOld)
1585        );
1586    }
1587
1588    #[test]
1589    fn test_check_slots_are_valid_next_vote() {
1590        let mut vote_state = VoteState::default();
1591
1592        let vote = Vote::new(vec![0], Hash::default());
1593        let slot_hashes: Vec<_> = vec![(*vote.slots.last().unwrap(), vote.hash)];
1594        assert_eq!(vote_state.process_vote(&vote, &slot_hashes, 0), Ok(()));
1595
1596        let vote = Vote::new(vec![0, 1], Hash::default());
1597        let slot_hashes: Vec<_> = vec![(1, vote.hash), (0, vote.hash)];
1598        assert_eq!(
1599            vote_state.check_slots_are_valid(&vote, &slot_hashes),
1600            Ok(())
1601        );
1602    }
1603
1604    #[test]
1605    fn test_check_slots_are_valid_next_vote_only() {
1606        let mut vote_state = VoteState::default();
1607
1608        let vote = Vote::new(vec![0], Hash::default());
1609        let slot_hashes: Vec<_> = vec![(*vote.slots.last().unwrap(), vote.hash)];
1610        assert_eq!(vote_state.process_vote(&vote, &slot_hashes, 0), Ok(()));
1611
1612        let vote = Vote::new(vec![1], Hash::default());
1613        let slot_hashes: Vec<_> = vec![(1, vote.hash), (0, vote.hash)];
1614        assert_eq!(
1615            vote_state.check_slots_are_valid(&vote, &slot_hashes),
1616            Ok(())
1617        );
1618    }
1619    #[test]
1620    fn test_process_vote_empty_slots() {
1621        let mut vote_state = VoteState::default();
1622
1623        let vote = Vote::new(vec![], Hash::default());
1624        assert_eq!(
1625            vote_state.process_vote(&vote, &[], 0),
1626            Err(VoteError::EmptySlots)
1627        );
1628    }
1629
1630    #[test]
1631    fn test_vote_state_commission_split() {
1632        let vote_state = VoteState::default();
1633
1634        assert_eq!(vote_state.commission_split(1), (0, 1, false));
1635
1636        let mut vote_state = VoteState {
1637            commission: std::u8::MAX,
1638            ..VoteState::default()
1639        };
1640        assert_eq!(vote_state.commission_split(1), (1, 0, false));
1641
1642        vote_state.commission = 99;
1643        assert_eq!(vote_state.commission_split(10), (9, 0, true));
1644
1645        vote_state.commission = 1;
1646        assert_eq!(vote_state.commission_split(10), (0, 9, true));
1647
1648        vote_state.commission = 50;
1649        let (voter_portion, staker_portion, was_split) = vote_state.commission_split(10);
1650
1651        assert_eq!((voter_portion, staker_portion, was_split), (5, 5, true));
1652    }
1653
1654    #[test]
1655    fn test_vote_state_withdraw() {
1656        let (vote_pubkey, vote_account) = create_test_account();
1657
1658        // unsigned request
1659        let keyed_accounts = &[KeyedAccount::new(&vote_pubkey, false, &vote_account)];
1660        let signers: HashSet<Pubkey> = get_signers(keyed_accounts);
1661        let res = withdraw(
1662            &keyed_accounts[0],
1663            0,
1664            &KeyedAccount::new(
1665                &gemachain_sdk::pubkey::new_rand(),
1666                false,
1667                &RefCell::new(AccountSharedData::default()),
1668            ),
1669            &signers,
1670        );
1671        assert_eq!(res, Err(InstructionError::MissingRequiredSignature));
1672
1673        // insufficient funds
1674        let keyed_accounts = &[KeyedAccount::new(&vote_pubkey, true, &vote_account)];
1675        let signers: HashSet<Pubkey> = get_signers(keyed_accounts);
1676        let res = withdraw(
1677            &keyed_accounts[0],
1678            101,
1679            &KeyedAccount::new(
1680                &gemachain_sdk::pubkey::new_rand(),
1681                false,
1682                &RefCell::new(AccountSharedData::default()),
1683            ),
1684            &signers,
1685        );
1686        assert_eq!(res, Err(InstructionError::InsufficientFunds));
1687
1688        // all good
1689        let to_account = RefCell::new(AccountSharedData::default());
1690        let carats = vote_account.borrow().carats();
1691        let keyed_accounts = &[KeyedAccount::new(&vote_pubkey, true, &vote_account)];
1692        let signers: HashSet<Pubkey> = get_signers(keyed_accounts);
1693        let pre_state: VoteStateVersions = vote_account.borrow().state().unwrap();
1694        let res = withdraw(
1695            &keyed_accounts[0],
1696            carats,
1697            &KeyedAccount::new(&gemachain_sdk::pubkey::new_rand(), false, &to_account),
1698            &signers,
1699        );
1700        assert_eq!(res, Ok(()));
1701        assert_eq!(vote_account.borrow().carats(), 0);
1702        assert_eq!(to_account.borrow().carats(), carats);
1703        let post_state: VoteStateVersions = vote_account.borrow().state().unwrap();
1704        // State has been deinitialized since balance is zero
1705        assert!(post_state.is_uninitialized());
1706
1707        // reset balance and restore state, verify that authorized_withdrawer works
1708        vote_account.borrow_mut().set_carats(carats);
1709        vote_account.borrow_mut().set_state(&pre_state).unwrap();
1710
1711        // authorize authorized_withdrawer
1712        let authorized_withdrawer_pubkey = gemachain_sdk::pubkey::new_rand();
1713        let keyed_accounts = &[KeyedAccount::new(&vote_pubkey, true, &vote_account)];
1714        let signers: HashSet<Pubkey> = get_signers(keyed_accounts);
1715        let res = authorize(
1716            &keyed_accounts[0],
1717            &authorized_withdrawer_pubkey,
1718            VoteAuthorize::Withdrawer,
1719            &signers,
1720            &Clock::default(),
1721        );
1722        assert_eq!(res, Ok(()));
1723
1724        // withdraw using authorized_withdrawer to authorized_withdrawer's account
1725        let withdrawer_account = RefCell::new(AccountSharedData::default());
1726        let keyed_accounts = &[
1727            KeyedAccount::new(&vote_pubkey, false, &vote_account),
1728            KeyedAccount::new(&authorized_withdrawer_pubkey, true, &withdrawer_account),
1729        ];
1730        let signers: HashSet<Pubkey> = get_signers(keyed_accounts);
1731        let vote_keyed_account = keyed_account_at_index(keyed_accounts, 0).unwrap();
1732        let withdrawer_keyed_account = keyed_account_at_index(keyed_accounts, 1).unwrap();
1733        let res = withdraw(
1734            vote_keyed_account,
1735            carats,
1736            withdrawer_keyed_account,
1737            &signers,
1738        );
1739        assert_eq!(res, Ok(()));
1740        assert_eq!(vote_account.borrow().carats(), 0);
1741        assert_eq!(withdrawer_account.borrow().carats(), carats);
1742        let post_state: VoteStateVersions = vote_account.borrow().state().unwrap();
1743        // State has been deinitialized since balance is zero
1744        assert!(post_state.is_uninitialized());
1745    }
1746
1747    #[test]
1748    fn test_vote_state_epoch_credits() {
1749        let mut vote_state = VoteState::default();
1750
1751        assert_eq!(vote_state.credits(), 0);
1752        assert_eq!(vote_state.epoch_credits().clone(), vec![]);
1753
1754        let mut expected = vec![];
1755        let mut credits = 0;
1756        let epochs = (MAX_EPOCH_CREDITS_HISTORY + 2) as u64;
1757        for epoch in 0..epochs {
1758            for _j in 0..epoch {
1759                vote_state.increment_credits(epoch);
1760                credits += 1;
1761            }
1762            expected.push((epoch, credits, credits - epoch));
1763        }
1764
1765        while expected.len() > MAX_EPOCH_CREDITS_HISTORY {
1766            expected.remove(0);
1767        }
1768
1769        assert_eq!(vote_state.credits(), credits);
1770        assert_eq!(vote_state.epoch_credits().clone(), expected);
1771    }
1772
1773    #[test]
1774    fn test_vote_state_epoch0_no_credits() {
1775        let mut vote_state = VoteState::default();
1776
1777        assert_eq!(vote_state.epoch_credits().len(), 0);
1778        vote_state.increment_credits(1);
1779        assert_eq!(vote_state.epoch_credits().len(), 1);
1780
1781        vote_state.increment_credits(2);
1782        assert_eq!(vote_state.epoch_credits().len(), 2);
1783    }
1784
1785    #[test]
1786    fn test_vote_state_increment_credits() {
1787        let mut vote_state = VoteState::default();
1788
1789        let credits = (MAX_EPOCH_CREDITS_HISTORY + 2) as u64;
1790        for i in 0..credits {
1791            vote_state.increment_credits(i as u64);
1792        }
1793        assert_eq!(vote_state.credits(), credits);
1794        assert!(vote_state.epoch_credits().len() <= MAX_EPOCH_CREDITS_HISTORY);
1795    }
1796
1797    #[test]
1798    fn test_vote_process_timestamp() {
1799        let (slot, timestamp) = (15, 1_575_412_285);
1800        let mut vote_state = VoteState {
1801            last_timestamp: BlockTimestamp { slot, timestamp },
1802            ..VoteState::default()
1803        };
1804
1805        assert_eq!(
1806            vote_state.process_timestamp(slot - 1, timestamp + 1),
1807            Err(VoteError::TimestampTooOld)
1808        );
1809        assert_eq!(
1810            vote_state.last_timestamp,
1811            BlockTimestamp { slot, timestamp }
1812        );
1813        assert_eq!(
1814            vote_state.process_timestamp(slot + 1, timestamp - 1),
1815            Err(VoteError::TimestampTooOld)
1816        );
1817        assert_eq!(
1818            vote_state.process_timestamp(slot, timestamp + 1),
1819            Err(VoteError::TimestampTooOld)
1820        );
1821        assert_eq!(vote_state.process_timestamp(slot, timestamp), Ok(()));
1822        assert_eq!(
1823            vote_state.last_timestamp,
1824            BlockTimestamp { slot, timestamp }
1825        );
1826        assert_eq!(vote_state.process_timestamp(slot + 1, timestamp), Ok(()));
1827        assert_eq!(
1828            vote_state.last_timestamp,
1829            BlockTimestamp {
1830                slot: slot + 1,
1831                timestamp
1832            }
1833        );
1834        assert_eq!(
1835            vote_state.process_timestamp(slot + 2, timestamp + 1),
1836            Ok(())
1837        );
1838        assert_eq!(
1839            vote_state.last_timestamp,
1840            BlockTimestamp {
1841                slot: slot + 2,
1842                timestamp: timestamp + 1
1843            }
1844        );
1845
1846        // Test initial vote
1847        vote_state.last_timestamp = BlockTimestamp::default();
1848        assert_eq!(vote_state.process_timestamp(0, timestamp), Ok(()));
1849    }
1850
1851    #[test]
1852    fn test_get_and_update_authorized_voter() {
1853        let original_voter = gemachain_sdk::pubkey::new_rand();
1854        let mut vote_state = VoteState::new(
1855            &VoteInit {
1856                node_pubkey: original_voter,
1857                authorized_voter: original_voter,
1858                authorized_withdrawer: original_voter,
1859                commission: 0,
1860            },
1861            &Clock::default(),
1862        );
1863
1864        // If no new authorized voter was set, the same authorized voter
1865        // is locked into the next epoch
1866        assert_eq!(
1867            vote_state.get_and_update_authorized_voter(1).unwrap(),
1868            original_voter
1869        );
1870
1871        // Try to get the authorized voter for epoch 5, implies
1872        // the authorized voter for epochs 1-4 were unchanged
1873        assert_eq!(
1874            vote_state.get_and_update_authorized_voter(5).unwrap(),
1875            original_voter
1876        );
1877
1878        // Authorized voter for expired epoch 0..5 should have been
1879        // purged and no longer queryable
1880        assert_eq!(vote_state.authorized_voters.len(), 1);
1881        for i in 0..5 {
1882            assert!(vote_state
1883                .authorized_voters
1884                .get_authorized_voter(i)
1885                .is_none());
1886        }
1887
1888        // Set an authorized voter change at slot 7
1889        let new_authorized_voter = gemachain_sdk::pubkey::new_rand();
1890        vote_state
1891            .set_new_authorized_voter(&new_authorized_voter, 5, 7, |_| Ok(()))
1892            .unwrap();
1893
1894        // Try to get the authorized voter for epoch 6, unchanged
1895        assert_eq!(
1896            vote_state.get_and_update_authorized_voter(6).unwrap(),
1897            original_voter
1898        );
1899
1900        // Try to get the authorized voter for epoch 7 and onwards, should
1901        // be the new authorized voter
1902        for i in 7..10 {
1903            assert_eq!(
1904                vote_state.get_and_update_authorized_voter(i).unwrap(),
1905                new_authorized_voter
1906            );
1907        }
1908        assert_eq!(vote_state.authorized_voters.len(), 1);
1909    }
1910
1911    #[test]
1912    fn test_set_new_authorized_voter() {
1913        let original_voter = gemachain_sdk::pubkey::new_rand();
1914        let epoch_offset = 15;
1915        let mut vote_state = VoteState::new(
1916            &VoteInit {
1917                node_pubkey: original_voter,
1918                authorized_voter: original_voter,
1919                authorized_withdrawer: original_voter,
1920                commission: 0,
1921            },
1922            &Clock::default(),
1923        );
1924
1925        assert!(vote_state.prior_voters.last().is_none());
1926
1927        let new_voter = gemachain_sdk::pubkey::new_rand();
1928        // Set a new authorized voter
1929        vote_state
1930            .set_new_authorized_voter(&new_voter, 0, epoch_offset, |_| Ok(()))
1931            .unwrap();
1932
1933        assert_eq!(vote_state.prior_voters.idx, 0);
1934        assert_eq!(
1935            vote_state.prior_voters.last(),
1936            Some(&(original_voter, 0, epoch_offset))
1937        );
1938
1939        // Trying to set authorized voter for same epoch again should fail
1940        assert_eq!(
1941            vote_state.set_new_authorized_voter(&new_voter, 0, epoch_offset, |_| Ok(())),
1942            Err(VoteError::TooSoonToReauthorize.into())
1943        );
1944
1945        // Setting the same authorized voter again should succeed
1946        vote_state
1947            .set_new_authorized_voter(&new_voter, 2, 2 + epoch_offset, |_| Ok(()))
1948            .unwrap();
1949
1950        // Set a third and fourth authorized voter
1951        let new_voter2 = gemachain_sdk::pubkey::new_rand();
1952        vote_state
1953            .set_new_authorized_voter(&new_voter2, 3, 3 + epoch_offset, |_| Ok(()))
1954            .unwrap();
1955        assert_eq!(vote_state.prior_voters.idx, 1);
1956        assert_eq!(
1957            vote_state.prior_voters.last(),
1958            Some(&(new_voter, epoch_offset, 3 + epoch_offset))
1959        );
1960
1961        let new_voter3 = gemachain_sdk::pubkey::new_rand();
1962        vote_state
1963            .set_new_authorized_voter(&new_voter3, 6, 6 + epoch_offset, |_| Ok(()))
1964            .unwrap();
1965        assert_eq!(vote_state.prior_voters.idx, 2);
1966        assert_eq!(
1967            vote_state.prior_voters.last(),
1968            Some(&(new_voter2, 3 + epoch_offset, 6 + epoch_offset))
1969        );
1970
1971        // Check can set back to original voter
1972        vote_state
1973            .set_new_authorized_voter(&original_voter, 9, 9 + epoch_offset, |_| Ok(()))
1974            .unwrap();
1975
1976        // Run with these voters for a while, check the ranges of authorized
1977        // voters is correct
1978        for i in 9..epoch_offset {
1979            assert_eq!(
1980                vote_state.get_and_update_authorized_voter(i).unwrap(),
1981                original_voter
1982            );
1983        }
1984        for i in epoch_offset..3 + epoch_offset {
1985            assert_eq!(
1986                vote_state.get_and_update_authorized_voter(i).unwrap(),
1987                new_voter
1988            );
1989        }
1990        for i in 3 + epoch_offset..6 + epoch_offset {
1991            assert_eq!(
1992                vote_state.get_and_update_authorized_voter(i).unwrap(),
1993                new_voter2
1994            );
1995        }
1996        for i in 6 + epoch_offset..9 + epoch_offset {
1997            assert_eq!(
1998                vote_state.get_and_update_authorized_voter(i).unwrap(),
1999                new_voter3
2000            );
2001        }
2002        for i in 9 + epoch_offset..=10 + epoch_offset {
2003            assert_eq!(
2004                vote_state.get_and_update_authorized_voter(i).unwrap(),
2005                original_voter
2006            );
2007        }
2008    }
2009
2010    #[test]
2011    fn test_authorized_voter_is_locked_within_epoch() {
2012        let original_voter = gemachain_sdk::pubkey::new_rand();
2013        let mut vote_state = VoteState::new(
2014            &VoteInit {
2015                node_pubkey: original_voter,
2016                authorized_voter: original_voter,
2017                authorized_withdrawer: original_voter,
2018                commission: 0,
2019            },
2020            &Clock::default(),
2021        );
2022
2023        // Test that it's not possible to set a new authorized
2024        // voter within the same epoch, even if none has been
2025        // explicitly set before
2026        let new_voter = gemachain_sdk::pubkey::new_rand();
2027        assert_eq!(
2028            vote_state.set_new_authorized_voter(&new_voter, 1, 1, |_| Ok(())),
2029            Err(VoteError::TooSoonToReauthorize.into())
2030        );
2031
2032        assert_eq!(vote_state.get_authorized_voter(1), Some(original_voter));
2033
2034        // Set a new authorized voter for a future epoch
2035        assert_eq!(
2036            vote_state.set_new_authorized_voter(&new_voter, 1, 2, |_| Ok(())),
2037            Ok(())
2038        );
2039
2040        // Test that it's not possible to set a new authorized
2041        // voter within the same epoch, even if none has been
2042        // explicitly set before
2043        assert_eq!(
2044            vote_state.set_new_authorized_voter(&original_voter, 3, 3, |_| Ok(())),
2045            Err(VoteError::TooSoonToReauthorize.into())
2046        );
2047
2048        assert_eq!(vote_state.get_authorized_voter(3), Some(new_voter));
2049    }
2050
2051    #[test]
2052    fn test_vote_state_max_size() {
2053        let mut max_sized_data = vec![0; VoteState::size_of()];
2054        let vote_state = VoteState::get_max_sized_vote_state();
2055        let (start_leader_schedule_epoch, _) = vote_state.authorized_voters.last().unwrap();
2056        let start_current_epoch =
2057            start_leader_schedule_epoch - MAX_LEADER_SCHEDULE_EPOCH_OFFSET + 1;
2058
2059        let mut vote_state = Some(vote_state);
2060        for i in start_current_epoch..start_current_epoch + 2 * MAX_LEADER_SCHEDULE_EPOCH_OFFSET {
2061            vote_state.as_mut().map(|vote_state| {
2062                vote_state.set_new_authorized_voter(
2063                    &gemachain_sdk::pubkey::new_rand(),
2064                    i,
2065                    i + MAX_LEADER_SCHEDULE_EPOCH_OFFSET,
2066                    |_| Ok(()),
2067                )
2068            });
2069
2070            let versioned = VoteStateVersions::new_current(vote_state.take().unwrap());
2071            VoteState::serialize(&versioned, &mut max_sized_data).unwrap();
2072            vote_state = Some(versioned.convert_to_current());
2073        }
2074    }
2075
2076    #[test]
2077    fn test_default_vote_state_is_uninitialized() {
2078        // The default `VoteState` is stored to de-initialize a zero-balance vote account,
2079        // so must remain such that `VoteStateVersions::is_uninitialized()` returns true
2080        // when called on a `VoteStateVersions` that stores it
2081        assert!(VoteStateVersions::new_current(VoteState::default()).is_uninitialized());
2082    }
2083
2084    #[test]
2085    fn test_is_uninitialized_no_deser() {
2086        // Check all zeroes
2087        let mut vote_account_data = vec![0; VoteState::size_of()];
2088        assert!(VoteState::is_uninitialized_no_deser(&vote_account_data));
2089
2090        // Check default VoteState
2091        let default_account_state = VoteStateVersions::new_current(VoteState::default());
2092        VoteState::serialize(&default_account_state, &mut vote_account_data).unwrap();
2093        assert!(VoteState::is_uninitialized_no_deser(&vote_account_data));
2094
2095        // Check non-zero data shorter than offset index used
2096        let short_data = vec![1; DEFAULT_PRIOR_VOTERS_OFFSET];
2097        assert!(VoteState::is_uninitialized_no_deser(&short_data));
2098
2099        // Check non-zero large account
2100        let mut large_vote_data = vec![1; 2 * VoteState::size_of()];
2101        let default_account_state = VoteStateVersions::new_current(VoteState::default());
2102        VoteState::serialize(&default_account_state, &mut large_vote_data).unwrap();
2103        assert!(VoteState::is_uninitialized_no_deser(&vote_account_data));
2104
2105        // Check populated VoteState
2106        let account_state = VoteStateVersions::new_current(VoteState::new(
2107            &VoteInit {
2108                node_pubkey: Pubkey::new_unique(),
2109                authorized_voter: Pubkey::new_unique(),
2110                authorized_withdrawer: Pubkey::new_unique(),
2111                commission: 0,
2112            },
2113            &Clock::default(),
2114        ));
2115        VoteState::serialize(&account_state, &mut vote_account_data).unwrap();
2116        assert!(!VoteState::is_uninitialized_no_deser(&vote_account_data));
2117    }
2118}