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
This commit is contained in:
Tyera 2024-04-01 19:41:48 -06:00 committed by GitHub
parent c29a2392fc
commit 16c684ef9f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 162 additions and 156 deletions

View File

@ -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| {

View File

@ -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::<Vec<_>>();
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]

View File

@ -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());
}
}

View File

@ -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.