1use 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
29pub const MAX_LOCKOUT_HISTORY: usize = 31;
31pub const INITIAL_LOCKOUT: usize = 2;
32
33pub const MAX_EPOCH_CREDITS_HISTORY: usize = 64;
35
36const 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 pub slots: Vec<Slot>,
44 pub hash: Hash,
46 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 pub fn lockout(&self) -> u64 {
84 (INITIAL_LOCKOUT as u64).pow(self.confirmation_count)
85 }
86
87 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
119const MAX_ITEMS: usize = 32;
121
122#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone, AbiExample)]
123pub struct CircBuf<I> {
124 buf: [I; MAX_ITEMS],
125 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 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 pub node_pubkey: Pubkey,
168
169 pub authorized_withdrawer: Pubkey,
171 pub commission: u8,
174
175 pub votes: VecDeque<Lockout>,
176
177 pub root_slot: Option<Slot>,
180
181 authorized_voters: AuthorizedVoters,
183
184 prior_voters: CircBuf<(Pubkey, Epoch, Epoch)>,
188
189 epoch_credits: Vec<(Epoch, u64, u64)>,
192
193 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 let vote_state = VoteStateVersions::new_current(Self::get_max_sized_vote_state());
228 serialized_size(&vote_state).unwrap() as usize
229 }
230
231 pub fn from<T: ReadableAccount>(account: &T) -> Option<VoteState> {
233 Self::deserialize(account.data()).ok()
234 }
235
236 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 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 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; let mut j = slot_hashes.len(); while i < vote.slots.len() && j > 0 {
307 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 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 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 pub fn increment_credits(&mut self, epoch: Epoch) {
391 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 self.epoch_credits.push((epoch, credits, credits));
403 } else {
404 self.epoch_credits.last_mut().unwrap().0 = epoch;
406 }
407
408 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 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 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 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 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 if self.authorized_voters.contains(target_epoch) {
495 return Err(VoteError::TooSoonToReauthorize.into());
496 }
497
498 let (latest_epoch, latest_authorized_pubkey) = self
500 .authorized_voters
501 .last()
502 .ok_or(InstructionError::InvalidAccountData)?;
503
504 if latest_authorized_pubkey != authorized_pubkey {
508 let epoch_of_last_authorized_switch =
510 self.prior_voters.last().map(|range| range.2).unwrap_or(0);
511
512 assert!(target_epoch > *latest_epoch);
519
520 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 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 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
596pub 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 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
628pub 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 verify_authorized_signer(&vote_state.authorized_withdrawer, signers)?;
639
640 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
648pub 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 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
676pub 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 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
705pub 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 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
785pub 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 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 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 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 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 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 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 assert_eq!(
1038 simulate_process_vote(&vote_pubkey, &vote_account, &vote, &[(1, hash)], 0),
1039 Err(VoteError::SlotsMismatch.into())
1040 );
1041
1042 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 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 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 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 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 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 epoch: 3,
1242 leader_schedule_epoch: 4,
1243 ..Clock::default()
1244 },
1245 );
1246 assert_eq!(res, Ok(()));
1247
1248 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 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 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 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 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 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 vote_state
1366 .process_slot_vote_unchecked(vote_state.votes.front().unwrap().last_locked_out_slot());
1367 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 vote_state.process_slot_vote_unchecked((2 + INITIAL_LOCKOUT + 1) as u64);
1386 check_lockouts(&vote_state);
1387
1388 vote_state.process_slot_vote_unchecked((2 + INITIAL_LOCKOUT + 2) as u64);
1391 check_lockouts(&vote_state);
1392
1393 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 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 assert_eq!(vote_state.votes[0].slot, 0);
1417 assert_eq!(vote_state.votes[1].slot, expire_slot);
1418
1419 vote_state.process_slot_vote_unchecked(expire_slot + 1);
1421
1422 assert_eq!(vote_state.votes[0].confirmation_count, 3);
1424
1425 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 #[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 (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 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 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 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 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 assert!(post_state.is_uninitialized());
1706
1707 vote_account.borrow_mut().set_carats(carats);
1709 vote_account.borrow_mut().set_state(&pre_state).unwrap();
1710
1711 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 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 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 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 assert_eq!(
1867 vote_state.get_and_update_authorized_voter(1).unwrap(),
1868 original_voter
1869 );
1870
1871 assert_eq!(
1874 vote_state.get_and_update_authorized_voter(5).unwrap(),
1875 original_voter
1876 );
1877
1878 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 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 assert_eq!(
1896 vote_state.get_and_update_authorized_voter(6).unwrap(),
1897 original_voter
1898 );
1899
1900 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 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 assert_eq!(
1941 vote_state.set_new_authorized_voter(&new_voter, 0, epoch_offset, |_| Ok(())),
1942 Err(VoteError::TooSoonToReauthorize.into())
1943 );
1944
1945 vote_state
1947 .set_new_authorized_voter(&new_voter, 2, 2 + epoch_offset, |_| Ok(()))
1948 .unwrap();
1949
1950 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 vote_state
1973 .set_new_authorized_voter(&original_voter, 9, 9 + epoch_offset, |_| Ok(()))
1974 .unwrap();
1975
1976 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 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 assert_eq!(
2036 vote_state.set_new_authorized_voter(&new_voter, 1, 2, |_| Ok(())),
2037 Ok(())
2038 );
2039
2040 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 assert!(VoteStateVersions::new_current(VoteState::default()).is_uninitialized());
2082 }
2083
2084 #[test]
2085 fn test_is_uninitialized_no_deser() {
2086 let mut vote_account_data = vec![0; VoteState::size_of()];
2088 assert!(VoteState::is_uninitialized_no_deser(&vote_account_data));
2089
2090 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 let short_data = vec![1; DEFAULT_PRIOR_VOTERS_OFFSET];
2097 assert!(VoteState::is_uninitialized_no_deser(&short_data));
2098
2099 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 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}