solana_sysvar/
epoch_rewards.rs

1//! Epoch rewards for current epoch
2//!
3//! The _epoch rewards_ sysvar provides access to the [`EpochRewards`] type,
4//! which tracks whether the rewards period (including calculation and
5//! distribution) is in progress, as well as the details needed to resume
6//! distribution when starting from a snapshot during the rewards period. The
7//! sysvar is repopulated at the start of the first block of each epoch.
8//! Therefore, the sysvar contains data about the current epoch until a new
9//! epoch begins. Fields in the sysvar include:
10//!   - distribution starting block height
11//!   - the number of partitions in the distribution
12//!   - the parent-blockhash seed used to generate the partition hasher
13//!   - the total rewards points calculated for the epoch
14//!   - total rewards for epoch, in lamports
15//!   - rewards for the epoch distributed so far, in lamports
16//!   - whether the rewards period is active
17//!
18//! [`EpochRewards`] implements [`Sysvar::get`] and can be loaded efficiently without
19//! passing the sysvar account ID to the program.
20//!
21//! See also the Solana [documentation on the epoch rewards sysvar][sdoc].
22//!
23//! [sdoc]: https://docs.solanalabs.com/runtime/sysvars#epochrewards
24//!
25//! # Examples
26//!
27//! Accessing via on-chain program directly:
28//!
29//! ```no_run
30//! # use solana_account_info::AccountInfo;
31//! # use solana_epoch_rewards::EpochRewards;
32//! # use solana_msg::msg;
33//! # use solana_program_error::{ProgramError, ProgramResult};
34//! # use solana_pubkey::Pubkey;
35//! # use solana_sysvar::Sysvar;
36//! # use solana_sdk_ids::sysvar::epoch_rewards;
37//! fn process_instruction(
38//!     program_id: &Pubkey,
39//!     accounts: &[AccountInfo],
40//!     instruction_data: &[u8],
41//! ) -> ProgramResult {
42//!
43//!     let epoch_rewards = EpochRewards::get()?;
44//!     msg!("epoch_rewards: {:#?}", epoch_rewards);
45//!
46//!     Ok(())
47//! }
48//! #
49//! # use solana_sysvar_id::SysvarId;
50//! # let p = EpochRewards::id();
51//! # let l = &mut 1559040;
52//! # let epoch_rewards = EpochRewards {
53//! #     distribution_starting_block_height: 42,
54//! #     total_rewards: 100,
55//! #     distributed_rewards: 10,
56//! #     active: true,
57//! #     ..EpochRewards::default()
58//! # };
59//! # let mut d: Vec<u8> = bincode::serialize(&epoch_rewards).unwrap();
60//! # let a = AccountInfo::new(&p, false, false, l, &mut d, &p, false);
61//! # let accounts = &[a.clone(), a];
62//! # process_instruction(
63//! #     &Pubkey::new_unique(),
64//! #     accounts,
65//! #     &[],
66//! # )?;
67//! # Ok::<(), ProgramError>(())
68//! ```
69//!
70//! Accessing via on-chain program's account parameters:
71//!
72//! ```
73//! # use solana_account_info::{AccountInfo, next_account_info};
74//! # use solana_epoch_rewards::EpochRewards;
75//! # use solana_msg::msg;
76//! # use solana_program_error::{ProgramError, ProgramResult};
77//! # use solana_pubkey::Pubkey;
78//! # use solana_sysvar::{Sysvar, SysvarSerialize};
79//! # use solana_sdk_ids::sysvar::epoch_rewards;
80//! #
81//! fn process_instruction(
82//!     program_id: &Pubkey,
83//!     accounts: &[AccountInfo],
84//!     instruction_data: &[u8],
85//! ) -> ProgramResult {
86//!     let account_info_iter = &mut accounts.iter();
87//!     let epoch_rewards_account_info = next_account_info(account_info_iter)?;
88//!
89//!     assert!(epoch_rewards::check_id(epoch_rewards_account_info.key));
90//!
91//!     let epoch_rewards = EpochRewards::from_account_info(epoch_rewards_account_info)?;
92//!     msg!("epoch_rewards: {:#?}", epoch_rewards);
93//!
94//!     Ok(())
95//! }
96//! #
97//! # use solana_sysvar_id::SysvarId;
98//! # let p = EpochRewards::id();
99//! # let l = &mut 1559040;
100//! # let epoch_rewards = EpochRewards {
101//! #     distribution_starting_block_height: 42,
102//! #     total_rewards: 100,
103//! #     distributed_rewards: 10,
104//! #     active: true,
105//! #     ..EpochRewards::default()
106//! # };
107//! # let mut d: Vec<u8> = bincode::serialize(&epoch_rewards).unwrap();
108//! # let a = AccountInfo::new(&p, false, false, l, &mut d, &p, false);
109//! # let accounts = &[a.clone(), a];
110//! # process_instruction(
111//! #     &Pubkey::new_unique(),
112//! #     accounts,
113//! #     &[],
114//! # )?;
115//! # Ok::<(), ProgramError>(())
116//! ```
117//!
118//! Accessing via the RPC client:
119//!
120//! ```
121//! # use solana_epoch_rewards::EpochRewards;
122//! # use solana_example_mocks::solana_account;
123//! # use solana_example_mocks::solana_rpc_client;
124//! # use solana_rpc_client::rpc_client::RpcClient;
125//! # use solana_account::Account;
126//! # use solana_sdk_ids::sysvar::epoch_rewards;
127//! # use anyhow::Result;
128//! #
129//! fn print_sysvar_epoch_rewards(client: &RpcClient) -> Result<()> {
130//! #   let epoch_rewards = EpochRewards {
131//! #       distribution_starting_block_height: 42,
132//! #       total_rewards: 100,
133//! #       distributed_rewards: 10,
134//! #       active: true,
135//! #       ..EpochRewards::default()
136//! #   };
137//! #   let data: Vec<u8> = bincode::serialize(&epoch_rewards)?;
138//! #   client.set_get_account_response(epoch_rewards::ID, Account {
139//! #       lamports: 1120560,
140//! #       data,
141//! #       owner: solana_sdk_ids::system_program::ID,
142//! #       executable: false,
143//! # });
144//! #
145//!     let epoch_rewards = client.get_account(&epoch_rewards::ID)?;
146//!     let data: EpochRewards = bincode::deserialize(&epoch_rewards.data)?;
147//!
148//!     Ok(())
149//! }
150//! #
151//! # let client = RpcClient::new(String::new());
152//! # print_sysvar_epoch_rewards(&client)?;
153//! #
154//! # Ok::<(), anyhow::Error>(())
155//! ```
156
157#[cfg(feature = "bincode")]
158use crate::SysvarSerialize;
159use crate::{impl_sysvar_get, Sysvar};
160pub use {
161    solana_epoch_rewards::EpochRewards,
162    solana_sdk_ids::sysvar::epoch_rewards::{check_id, id, ID},
163};
164
165impl Sysvar for EpochRewards {
166    impl_sysvar_get!(id());
167}
168
169#[cfg(feature = "bincode")]
170impl SysvarSerialize for EpochRewards {}
171
172#[cfg(test)]
173mod tests {
174    use {super::*, crate::tests::to_bytes, serial_test::serial};
175
176    #[test]
177    #[serial]
178    fn test_epoch_rewards_get_uses_sysvar_syscall() {
179        let expected = EpochRewards {
180            distribution_starting_block_height: 42,
181            num_partitions: 7,
182            parent_blockhash: solana_hash::Hash::new_unique(),
183            total_points: 1234567890,
184            total_rewards: 100,
185            distributed_rewards: 10,
186            active: true,
187        };
188
189        let data = to_bytes(&expected);
190        crate::tests::mock_get_sysvar_syscall(&data);
191
192        let got = EpochRewards::get().unwrap();
193        assert_eq!(got, expected);
194    }
195}