solana_accounts_db/
stake_rewards.rs

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