From 16c684ef9f682501c831fc75510e519d1de3657b Mon Sep 17 00:00:00 2001 From: Tyera Date: Mon, 1 Apr 2024 19:41:48 -0600 Subject: [PATCH] Move sysvar submodule; reorg partitioned epoch rewards runtime code, 2 of 5 (#520) * Add sysvar sub-submodule * Move sysvar methods to sub-submodule * Move unit test to sysvar sub-submodule * Add new partitioned_epoch_rewards::sysvar method * Remove superfluous method --- runtime/src/bank.rs | 93 +---------- .../src/bank/partitioned_epoch_rewards/mod.rs | 20 +-- .../bank/partitioned_epoch_rewards/sysvar.rs | 154 ++++++++++++++++++ runtime/src/bank/tests.rs | 51 ------ 4 files changed, 162 insertions(+), 156 deletions(-) create mode 100644 runtime/src/bank/partitioned_epoch_rewards/sysvar.rs diff --git a/runtime/src/bank.rs b/runtime/src/bank.rs index 47a63b9fc..29c01da7e 100644 --- a/runtime/src/bank.rs +++ b/runtime/src/bank.rs @@ -1477,27 +1477,6 @@ impl Bank { ); } - /// partitioned reward distribution is complete. - /// So, deactivate the epoch rewards sysvar. - fn deactivate_epoch_reward_status(&mut self) { - assert!(matches!( - self.epoch_reward_status, - EpochRewardStatus::Active(_) - )); - self.epoch_reward_status = EpochRewardStatus::Inactive; - if let Some(account) = self.get_account(&sysvar::epoch_rewards::id()) { - if account.lamports() > 0 { - info!( - "burning {} extra lamports in EpochRewards sysvar account at slot {}", - account.lamports(), - self.slot() - ); - self.log_epoch_rewards_sysvar("burn"); - self.burn_and_purge_account(&sysvar::epoch_rewards::id(), account); - } - } - } - /// Begin the process of calculating and distributing rewards. /// This process can take multiple slots. fn begin_partitioned_rewards( @@ -1571,7 +1550,12 @@ impl Bank { ("start_block_height", start_block_height, i64), ); - self.deactivate_epoch_reward_status(); + assert!(matches!( + self.epoch_reward_status, + EpochRewardStatus::Active(_) + )); + self.epoch_reward_status = EpochRewardStatus::Inactive; + self.destroy_epoch_rewards_sysvar(); } } @@ -3440,71 +3424,6 @@ impl Bank { report_partitioned_reward_metrics(self, metrics); } - /// Helper fn to log epoch_rewards sysvar - 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: {:?}", - (account.lamports(), epoch_rewards) - ); - } else { - info!("{prefix} epoch_rewards sysvar: none"); - } - } - - /// Create EpochRewards sysvar with calculated rewards - fn create_epoch_rewards_sysvar( - &self, - total_rewards: u64, - distributed_rewards: u64, - distribution_starting_block_height: u64, - ) { - assert!(self.is_partitioned_rewards_code_enabled()); - - let epoch_rewards = sysvar::epoch_rewards::EpochRewards { - total_rewards, - distributed_rewards, - distribution_starting_block_height, - active: true, - ..sysvar::epoch_rewards::EpochRewards::default() - }; - - self.update_sysvar_account(&sysvar::epoch_rewards::id(), |account| { - let mut inherited_account_fields = - self.inherit_specially_retained_account_fields(account); - - assert!(total_rewards >= distributed_rewards); - // set the account lamports to the undistributed rewards - inherited_account_fields.0 = total_rewards - distributed_rewards; - create_account(&epoch_rewards, inherited_account_fields) - }); - - self.log_epoch_rewards_sysvar("create"); - } - - /// Update EpochRewards sysvar with distributed rewards - fn update_epoch_rewards_sysvar(&self, distributed: u64) { - assert!(self.is_partitioned_rewards_code_enabled()); - - let mut epoch_rewards: sysvar::epoch_rewards::EpochRewards = - from_account(&self.get_account(&sysvar::epoch_rewards::id()).unwrap()).unwrap(); - epoch_rewards.distribute(distributed); - - self.update_sysvar_account(&sysvar::epoch_rewards::id(), |account| { - let mut inherited_account_fields = - self.inherit_specially_retained_account_fields(account); - - let lamports = inherited_account_fields.0; - assert!(lamports >= distributed); - inherited_account_fields.0 = lamports - distributed; - create_account(&epoch_rewards, inherited_account_fields) - }); - - self.log_epoch_rewards_sysvar("update"); - } - fn update_recent_blockhashes_locked(&self, locked_blockhash_queue: &BlockhashQueue) { #[allow(deprecated)] self.update_sysvar_account(&sysvar::recent_blockhashes::id(), |account| { diff --git a/runtime/src/bank/partitioned_epoch_rewards/mod.rs b/runtime/src/bank/partitioned_epoch_rewards/mod.rs index 21f4fdcab..5d7f405e3 100644 --- a/runtime/src/bank/partitioned_epoch_rewards/mod.rs +++ b/runtime/src/bank/partitioned_epoch_rewards/mod.rs @@ -1,3 +1,5 @@ +mod sysvar; + use { super::Bank, crate::{stake_account::StakeAccount, stake_history::StakeHistory}, @@ -232,24 +234,6 @@ mod tests { assert!(bank.is_partitioned_rewards_feature_enabled()); } - #[test] - fn test_deactivate_epoch_reward_status() { - let (genesis_config, _mint_keypair) = create_genesis_config(1_000_000 * LAMPORTS_PER_SOL); - let mut bank = Bank::new_for_tests(&genesis_config); - - let expected_num = 100; - - let stake_rewards = (0..expected_num) - .map(|_| StakeReward::new_random()) - .collect::>(); - - bank.set_epoch_reward_status_active(vec![stake_rewards]); - - assert!(bank.get_reward_interval() == RewardInterval::InsideInterval); - bank.deactivate_epoch_reward_status(); - assert!(bank.get_reward_interval() == RewardInterval::OutsideInterval); - } - /// Test get_reward_distribution_num_blocks, get_reward_calculation_num_blocks, get_reward_total_num_blocks during small epoch /// The num_credit_blocks should be cap to 10% of the total number of blocks in the epoch. #[test] diff --git a/runtime/src/bank/partitioned_epoch_rewards/sysvar.rs b/runtime/src/bank/partitioned_epoch_rewards/sysvar.rs new file mode 100644 index 000000000..b540dc2be --- /dev/null +++ b/runtime/src/bank/partitioned_epoch_rewards/sysvar.rs @@ -0,0 +1,154 @@ +use { + super::Bank, + log::info, + solana_sdk::{ + account::{ + create_account_shared_data_with_fields as create_account, from_account, ReadableAccount, + }, + sysvar, + }, +}; + +impl Bank { + /// Helper fn to log epoch_rewards sysvar + 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: {:?}", + (account.lamports(), epoch_rewards) + ); + } else { + info!("{prefix} epoch_rewards sysvar: none"); + } + } + + /// Create EpochRewards sysvar with calculated rewards + pub(in crate::bank) fn create_epoch_rewards_sysvar( + &self, + total_rewards: u64, + distributed_rewards: u64, + distribution_starting_block_height: u64, + ) { + assert!(self.is_partitioned_rewards_code_enabled()); + + let epoch_rewards = sysvar::epoch_rewards::EpochRewards { + total_rewards, + distributed_rewards, + distribution_starting_block_height, + active: true, + ..sysvar::epoch_rewards::EpochRewards::default() + }; + + self.update_sysvar_account(&sysvar::epoch_rewards::id(), |account| { + let mut inherited_account_fields = + self.inherit_specially_retained_account_fields(account); + + assert!(total_rewards >= distributed_rewards); + // set the account lamports to the undistributed rewards + inherited_account_fields.0 = total_rewards - distributed_rewards; + create_account(&epoch_rewards, inherited_account_fields) + }); + + self.log_epoch_rewards_sysvar("create"); + } + + /// Update EpochRewards sysvar with distributed rewards + pub(in crate::bank) fn update_epoch_rewards_sysvar(&self, distributed: u64) { + assert!(self.is_partitioned_rewards_code_enabled()); + + let mut epoch_rewards: sysvar::epoch_rewards::EpochRewards = + from_account(&self.get_account(&sysvar::epoch_rewards::id()).unwrap()).unwrap(); + epoch_rewards.distribute(distributed); + + self.update_sysvar_account(&sysvar::epoch_rewards::id(), |account| { + let mut inherited_account_fields = + self.inherit_specially_retained_account_fields(account); + + let lamports = inherited_account_fields.0; + assert!(lamports >= distributed); + inherited_account_fields.0 = lamports - distributed; + create_account(&epoch_rewards, inherited_account_fields) + }); + + self.log_epoch_rewards_sysvar("update"); + } + + pub(in crate::bank) fn destroy_epoch_rewards_sysvar(&self) { + if let Some(account) = self.get_account(&sysvar::epoch_rewards::id()) { + if account.lamports() > 0 { + info!( + "burning {} extra lamports in EpochRewards sysvar account at slot {}", + account.lamports(), + self.slot() + ); + self.log_epoch_rewards_sysvar("burn"); + self.burn_and_purge_account(&sysvar::epoch_rewards::id(), account); + } + } + } +} + +#[cfg(test)] +mod tests { + use { + super::*, + crate::bank::tests::create_genesis_config, + solana_sdk::{ + epoch_schedule::EpochSchedule, feature_set, hash::Hash, native_token::LAMPORTS_PER_SOL, + }, + }; + + /// Test `EpochRewards` sysvar creation, distribution, and burning. + /// This test covers the following epoch_rewards_sysvar bank member functions, i.e. + /// `create_epoch_rewards_sysvar`, `update_epoch_rewards_sysvar`, `burn_and_purge_account`. + #[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 mut bank = Bank::new_for_tests(&genesis_config); + bank.activate_feature(&feature_set::enable_partitioned_epoch_reward::id()); + + let total_rewards = 1_000_000_000; // a large rewards so that the sysvar account is rent-exempted. + + // create epoch rewards sysvar + let expected_epoch_rewards = sysvar::epoch_rewards::EpochRewards { + distribution_starting_block_height: 42, + num_partitions: 0, + parent_blockhash: Hash::default(), + total_points: 0, + total_rewards, + distributed_rewards: 10, + active: true, + }; + + bank.create_epoch_rewards_sysvar(total_rewards, 10, 42); + let account = bank.get_account(&sysvar::epoch_rewards::id()).unwrap(); + assert_eq!(account.lamports(), total_rewards - 10); + let epoch_rewards: sysvar::epoch_rewards::EpochRewards = from_account(&account).unwrap(); + assert_eq!(epoch_rewards, expected_epoch_rewards); + + // make a distribution from epoch rewards sysvar + bank.update_epoch_rewards_sysvar(10); + let account = bank.get_account(&sysvar::epoch_rewards::id()).unwrap(); + assert_eq!(account.lamports(), total_rewards - 20); + 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: 0, + parent_blockhash: Hash::default(), + total_points: 0, + total_rewards, + distributed_rewards: 20, + active: true, + }; + assert_eq!(epoch_rewards, expected_epoch_rewards); + + // burn epoch rewards sysvar + bank.burn_and_purge_account(&sysvar::epoch_rewards::id(), account); + let account = bank.get_account(&sysvar::epoch_rewards::id()); + assert!(account.is_none()); + } +} diff --git a/runtime/src/bank/tests.rs b/runtime/src/bank/tests.rs index 0b9f2757d..5b89de286 100644 --- a/runtime/src/bank/tests.rs +++ b/runtime/src/bank/tests.rs @@ -12650,57 +12650,6 @@ fn test_rewards_computation_and_partitioned_distribution_two_blocks() { } } -/// Test `EpochRewards` sysvar creation, distribution, and burning. -/// This test covers the following epoch_rewards_sysvar bank member functions, i.e. -/// `create_epoch_rewards_sysvar`, `update_epoch_rewards_sysvar`, `burn_and_purge_account`. -#[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 mut bank = Bank::new_for_tests(&genesis_config); - bank.activate_feature(&feature_set::enable_partitioned_epoch_reward::id()); - - let total_rewards = 1_000_000_000; // a large rewards so that the sysvar account is rent-exempted. - - // create epoch rewards sysvar - let expected_epoch_rewards = sysvar::epoch_rewards::EpochRewards { - distribution_starting_block_height: 42, - num_partitions: 0, - parent_blockhash: Hash::default(), - total_points: 0, - total_rewards, - distributed_rewards: 10, - active: true, - }; - - bank.create_epoch_rewards_sysvar(total_rewards, 10, 42); - let account = bank.get_account(&sysvar::epoch_rewards::id()).unwrap(); - assert_eq!(account.lamports(), total_rewards - 10); - let epoch_rewards: sysvar::epoch_rewards::EpochRewards = from_account(&account).unwrap(); - assert_eq!(epoch_rewards, expected_epoch_rewards); - - // make a distribution from epoch rewards sysvar - bank.update_epoch_rewards_sysvar(10); - let account = bank.get_account(&sysvar::epoch_rewards::id()).unwrap(); - assert_eq!(account.lamports(), total_rewards - 20); - 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: 0, - parent_blockhash: Hash::default(), - total_points: 0, - total_rewards, - distributed_rewards: 20, - active: true, - }; - assert_eq!(epoch_rewards, expected_epoch_rewards); - - // burn epoch rewards sysvar - bank.burn_and_purge_account(&sysvar::epoch_rewards::id(), account); - let account = bank.get_account(&sysvar::epoch_rewards::id()); - assert!(account.is_none()); -} - /// Test that program execution that involves stake accounts should fail during reward period. /// Any programs, which result in stake account changes, will throw `ProgramExecutionTemporarilyRestricted` error when /// in reward period.