solana_accounts_db/
stake_rewards.rs

1//! Code for stake and vote rewards
2
3use {
4    crate::storable_accounts::{AccountForStorage, StorableAccounts},
5    solana_pubkey::Pubkey,
6    solana_sdk::{account::AccountSharedData, clock::Slot, reward_info::RewardInfo},
7};
8
9#[cfg_attr(feature = "frozen-abi", derive(AbiExample))]
10#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
11pub struct StakeReward {
12    pub stake_pubkey: Pubkey,
13    pub stake_reward_info: RewardInfo,
14    pub stake_account: AccountSharedData,
15}
16
17impl StakeReward {
18    pub fn get_stake_reward(&self) -> i64 {
19        self.stake_reward_info.lamports
20    }
21}
22
23/// allow [StakeReward] to be passed to `StoreAccounts` directly without copies or vec construction
24impl<'a> StorableAccounts<'a> for (Slot, &'a [StakeReward]) {
25    fn account<Ret>(
26        &self,
27        index: usize,
28        mut callback: impl for<'local> FnMut(AccountForStorage<'local>) -> Ret,
29    ) -> Ret {
30        let entry = &self.1[index];
31        callback((&self.1[index].stake_pubkey, &entry.stake_account).into())
32    }
33    fn slot(&self, _index: usize) -> Slot {
34        // per-index slot is not unique per slot when per-account slot is not included in the source data
35        self.target_slot()
36    }
37    fn target_slot(&self) -> Slot {
38        self.0
39    }
40    fn len(&self) -> usize {
41        self.1.len()
42    }
43}
44
45#[cfg(feature = "dev-context-only-utils")]
46use {
47    rand::Rng,
48    solana_sdk::{
49        account::WritableAccount,
50        rent::Rent,
51        signature::{Keypair, Signer},
52    },
53    solana_stake_program::stake_state,
54    solana_vote_program::vote_state,
55};
56
57// These functions/fields are only usable from a dev context (i.e. tests and benches)
58#[cfg(feature = "dev-context-only-utils")]
59impl StakeReward {
60    pub fn new_random() -> Self {
61        let mut rng = rand::thread_rng();
62
63        let rent = Rent::free();
64
65        let validator_pubkey = solana_pubkey::new_rand();
66        let validator_stake_lamports = 20;
67        let validator_staking_keypair = Keypair::new();
68        let validator_voting_keypair = Keypair::new();
69
70        let validator_vote_account = vote_state::create_account(
71            &validator_voting_keypair.pubkey(),
72            &validator_pubkey,
73            10,
74            validator_stake_lamports,
75        );
76
77        let reward_lamports: i64 = rng.gen_range(1..200);
78        let validator_stake_account = stake_state::create_account(
79            &validator_staking_keypair.pubkey(),
80            &validator_voting_keypair.pubkey(),
81            &validator_vote_account,
82            &rent,
83            validator_stake_lamports + reward_lamports as u64,
84        );
85
86        Self {
87            stake_pubkey: Pubkey::new_unique(),
88            stake_reward_info: RewardInfo {
89                reward_type: solana_sdk::reward_type::RewardType::Staking,
90                lamports: reward_lamports,
91                post_balance: 0,  /* unused atm */
92                commission: None, /* unused atm */
93            },
94
95            stake_account: validator_stake_account,
96        }
97    }
98
99    pub fn credit(&mut self, amount: u64) {
100        self.stake_reward_info.lamports = amount as i64;
101        self.stake_reward_info.post_balance += amount;
102        self.stake_account.checked_add_lamports(amount).unwrap();
103    }
104}