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:
parent
c29a2392fc
commit
16c684ef9f
|
@ -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| {
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
|
@ -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.
|
||||
|
|
Loading…
Reference in New Issue