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.
|
/// Begin the process of calculating and distributing rewards.
|
||||||
/// This process can take multiple slots.
|
/// This process can take multiple slots.
|
||||||
fn begin_partitioned_rewards(
|
fn begin_partitioned_rewards(
|
||||||
|
@ -1571,7 +1550,12 @@ impl Bank {
|
||||||
("start_block_height", start_block_height, i64),
|
("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);
|
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) {
|
fn update_recent_blockhashes_locked(&self, locked_blockhash_queue: &BlockhashQueue) {
|
||||||
#[allow(deprecated)]
|
#[allow(deprecated)]
|
||||||
self.update_sysvar_account(&sysvar::recent_blockhashes::id(), |account| {
|
self.update_sysvar_account(&sysvar::recent_blockhashes::id(), |account| {
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
mod sysvar;
|
||||||
|
|
||||||
use {
|
use {
|
||||||
super::Bank,
|
super::Bank,
|
||||||
crate::{stake_account::StakeAccount, stake_history::StakeHistory},
|
crate::{stake_account::StakeAccount, stake_history::StakeHistory},
|
||||||
|
@ -232,24 +234,6 @@ mod tests {
|
||||||
assert!(bank.is_partitioned_rewards_feature_enabled());
|
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
|
/// 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.
|
/// The num_credit_blocks should be cap to 10% of the total number of blocks in the epoch.
|
||||||
#[test]
|
#[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.
|
/// 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
|
/// Any programs, which result in stake account changes, will throw `ProgramExecutionTemporarilyRestricted` error when
|
||||||
/// in reward period.
|
/// in reward period.
|
||||||
|
|
Loading…
Reference in New Issue