use {
super::Bank,
crate::inflation_rewards::points::PointValue,
log::info,
solana_account::{create_account_shared_data_with_fields as create_account, from_account},
solana_sysvar as sysvar,
};
impl Bank {
fn log_epoch_rewards_sysvar(&self, prefix: &str) {
if let Some(account) = self.get_account(&sysvar::epoch_rewards::id()) {
let epoch_rewards: sysvar::epoch_rewards::EpochRewards =
from_account(&account).unwrap();
info!("{prefix} epoch_rewards sysvar: {epoch_rewards:?}");
} else {
info!("{prefix} epoch_rewards sysvar: none");
}
}
pub(in crate::bank) fn create_epoch_rewards_sysvar(
&self,
distributed_rewards: u64,
distribution_starting_block_height: u64,
num_partitions: u64,
point_value: &PointValue,
) {
assert!(point_value.rewards >= distributed_rewards);
let parent_blockhash = self.last_blockhash();
let epoch_rewards = sysvar::epoch_rewards::EpochRewards {
distribution_starting_block_height,
num_partitions,
parent_blockhash,
total_points: point_value.points,
total_rewards: point_value.rewards,
distributed_rewards,
active: true,
};
self.update_sysvar_account(&sysvar::epoch_rewards::id(), |account| {
create_account(
&epoch_rewards,
self.inherit_specially_retained_account_fields(account),
)
});
self.log_epoch_rewards_sysvar("create");
}
pub(in crate::bank::partitioned_epoch_rewards) fn update_epoch_rewards_sysvar(
&self,
distributed: u64,
) {
let mut epoch_rewards = self.get_epoch_rewards_sysvar();
assert!(epoch_rewards.active);
epoch_rewards.distribute(distributed);
self.update_sysvar_account(&sysvar::epoch_rewards::id(), |account| {
create_account(
&epoch_rewards,
self.inherit_specially_retained_account_fields(account),
)
});
self.log_epoch_rewards_sysvar("update");
}
pub(in crate::bank::partitioned_epoch_rewards) fn set_epoch_rewards_sysvar_to_inactive(&self) {
let mut epoch_rewards = self.get_epoch_rewards_sysvar();
assert!(epoch_rewards.total_rewards >= epoch_rewards.distributed_rewards);
epoch_rewards.active = false;
self.update_sysvar_account(&sysvar::epoch_rewards::id(), |account| {
create_account(
&epoch_rewards,
self.inherit_specially_retained_account_fields(account),
)
});
self.log_epoch_rewards_sysvar("set_inactive");
}
pub(in crate::bank::partitioned_epoch_rewards) fn get_epoch_rewards_sysvar(
&self,
) -> sysvar::epoch_rewards::EpochRewards {
from_account(
&self
.get_account(&sysvar::epoch_rewards::id())
.unwrap_or_default(),
)
.unwrap_or_default()
}
}
#[cfg(test)]
mod tests {
use {
super::*, crate::bank::tests::create_genesis_config, solana_account::ReadableAccount,
solana_epoch_schedule::EpochSchedule, solana_native_token::LAMPORTS_PER_SOL,
solana_pubkey::Pubkey, std::sync::Arc,
};
#[test]
fn test_epoch_rewards_sysvar() {
let (mut genesis_config, _mint_keypair) =
create_genesis_config(1_000_000 * LAMPORTS_PER_SOL);
genesis_config.epoch_schedule = EpochSchedule::custom(432000, 432000, false);
let bank = Bank::new_for_tests(&genesis_config);
let total_rewards = 1_000_000_000;
let num_partitions = 2; let total_points = (total_rewards * 42) as u128; let point_value = PointValue {
rewards: total_rewards,
points: total_points,
};
let expected_epoch_rewards = sysvar::epoch_rewards::EpochRewards {
distribution_starting_block_height: 42,
num_partitions,
parent_blockhash: bank.last_blockhash(),
total_points,
total_rewards,
distributed_rewards: 10,
active: true,
};
let epoch_rewards = bank.get_epoch_rewards_sysvar();
assert_eq!(
epoch_rewards,
sysvar::epoch_rewards::EpochRewards::default()
);
bank.create_epoch_rewards_sysvar(10, 42, num_partitions, &point_value);
let account = bank.get_account(&sysvar::epoch_rewards::id()).unwrap();
let expected_balance = bank.get_minimum_balance_for_rent_exemption(account.data().len());
assert_eq!(account.lamports(), expected_balance);
let epoch_rewards: sysvar::epoch_rewards::EpochRewards = from_account(&account).unwrap();
assert_eq!(epoch_rewards, expected_epoch_rewards);
let parent_blockhash = bank.last_blockhash();
let parent_slot = bank.slot();
let bank = Bank::new_from_parent(Arc::new(bank), &Pubkey::default(), parent_slot + 1);
bank.create_epoch_rewards_sysvar(10, 42, num_partitions, &point_value);
let expected_epoch_rewards = sysvar::epoch_rewards::EpochRewards {
distribution_starting_block_height: 42,
num_partitions,
parent_blockhash,
total_points,
total_rewards,
distributed_rewards: 10,
active: true,
};
let epoch_rewards = bank.get_epoch_rewards_sysvar();
assert_eq!(epoch_rewards, expected_epoch_rewards);
bank.update_epoch_rewards_sysvar(10);
let account = bank.get_account(&sysvar::epoch_rewards::id()).unwrap();
assert_eq!(account.lamports(), expected_balance);
let epoch_rewards: sysvar::epoch_rewards::EpochRewards = from_account(&account).unwrap();
let expected_epoch_rewards = sysvar::epoch_rewards::EpochRewards {
distribution_starting_block_height: 42,
num_partitions,
parent_blockhash,
total_points,
total_rewards,
distributed_rewards: 20,
active: true,
};
assert_eq!(epoch_rewards, expected_epoch_rewards);
}
}