stake: Remove v2 program references (#19308)
* stake: Remove v2 program references * Remove stake v2 feature, along with stake rewrite
This commit is contained in:
@ -1,7 +1,6 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
cli::{CliCommand, CliCommandInfo, CliConfig, CliError, ProcessResult},
|
cli::{CliCommand, CliCommandInfo, CliConfig, CliError, ProcessResult},
|
||||||
spend_utils::{resolve_spend_tx_and_check_account_balance, SpendAmount},
|
spend_utils::{resolve_spend_tx_and_check_account_balance, SpendAmount},
|
||||||
stake::is_stake_program_v2_enabled,
|
|
||||||
};
|
};
|
||||||
use clap::{value_t, value_t_or_exit, App, AppSettings, Arg, ArgMatches, SubCommand};
|
use clap::{value_t, value_t_or_exit, App, AppSettings, Arg, ArgMatches, SubCommand};
|
||||||
use console::{style, Emoji};
|
use console::{style, Emoji};
|
||||||
@ -1749,8 +1748,6 @@ pub fn process_show_stakes(
|
|||||||
let stake_history = from_account(&stake_history_account).ok_or_else(|| {
|
let stake_history = from_account(&stake_history_account).ok_or_else(|| {
|
||||||
CliError::RpcRequestError("Failed to deserialize stake history".to_string())
|
CliError::RpcRequestError("Failed to deserialize stake history".to_string())
|
||||||
})?;
|
})?;
|
||||||
// At v1.6, this check can be removed and simply passed as `true`
|
|
||||||
let stake_program_v2_enabled = is_stake_program_v2_enabled(rpc_client)?;
|
|
||||||
|
|
||||||
let mut stake_accounts: Vec<CliKeyedStakeState> = vec![];
|
let mut stake_accounts: Vec<CliKeyedStakeState> = vec![];
|
||||||
for (stake_pubkey, stake_account) in all_stake_accounts {
|
for (stake_pubkey, stake_account) in all_stake_accounts {
|
||||||
@ -1766,7 +1763,6 @@ pub fn process_show_stakes(
|
|||||||
use_lamports_unit,
|
use_lamports_unit,
|
||||||
&stake_history,
|
&stake_history,
|
||||||
&clock,
|
&clock,
|
||||||
stake_program_v2_enabled,
|
|
||||||
),
|
),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -1785,7 +1781,6 @@ pub fn process_show_stakes(
|
|||||||
use_lamports_unit,
|
use_lamports_unit,
|
||||||
&stake_history,
|
&stake_history,
|
||||||
&clock,
|
&clock,
|
||||||
stake_program_v2_enabled,
|
|
||||||
),
|
),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -33,7 +33,6 @@ use solana_sdk::{
|
|||||||
account_utils::StateMut,
|
account_utils::StateMut,
|
||||||
clock::{Clock, UnixTimestamp, SECONDS_PER_DAY},
|
clock::{Clock, UnixTimestamp, SECONDS_PER_DAY},
|
||||||
epoch_schedule::EpochSchedule,
|
epoch_schedule::EpochSchedule,
|
||||||
feature, feature_set,
|
|
||||||
message::Message,
|
message::Message,
|
||||||
pubkey::Pubkey,
|
pubkey::Pubkey,
|
||||||
stake::{
|
stake::{
|
||||||
@ -1950,7 +1949,6 @@ pub fn build_stake_state(
|
|||||||
use_lamports_unit: bool,
|
use_lamports_unit: bool,
|
||||||
stake_history: &StakeHistory,
|
stake_history: &StakeHistory,
|
||||||
clock: &Clock,
|
clock: &Clock,
|
||||||
stake_program_v2_enabled: bool,
|
|
||||||
) -> CliStakeState {
|
) -> CliStakeState {
|
||||||
match stake_state {
|
match stake_state {
|
||||||
StakeState::Stake(
|
StakeState::Stake(
|
||||||
@ -1962,12 +1960,9 @@ pub fn build_stake_state(
|
|||||||
stake,
|
stake,
|
||||||
) => {
|
) => {
|
||||||
let current_epoch = clock.epoch;
|
let current_epoch = clock.epoch;
|
||||||
let (active_stake, activating_stake, deactivating_stake) =
|
let (active_stake, activating_stake, deactivating_stake) = stake
|
||||||
stake.delegation.stake_activating_and_deactivating(
|
.delegation
|
||||||
current_epoch,
|
.stake_activating_and_deactivating(current_epoch, Some(stake_history));
|
||||||
Some(stake_history),
|
|
||||||
stake_program_v2_enabled,
|
|
||||||
);
|
|
||||||
let lockup = if lockup.is_in_force(clock, None) {
|
let lockup = if lockup.is_in_force(clock, None) {
|
||||||
Some(lockup.into())
|
Some(lockup.into())
|
||||||
} else {
|
} else {
|
||||||
@ -2156,7 +2151,6 @@ pub fn process_show_stake_account(
|
|||||||
use_lamports_unit,
|
use_lamports_unit,
|
||||||
&stake_history,
|
&stake_history,
|
||||||
&clock,
|
&clock,
|
||||||
is_stake_program_v2_enabled(rpc_client)?, // At v1.6, this check can be removed and simply passed as `true`
|
|
||||||
);
|
);
|
||||||
|
|
||||||
if state.stake_type == CliStakeType::Stake && state.activation_epoch.is_some() {
|
if state.stake_type == CliStakeType::Stake && state.activation_epoch.is_some() {
|
||||||
@ -2338,15 +2332,6 @@ pub fn process_delegate_stake(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_stake_program_v2_enabled(
|
|
||||||
rpc_client: &RpcClient,
|
|
||||||
) -> Result<bool, Box<dyn std::error::Error>> {
|
|
||||||
let feature_account = rpc_client.get_account(&feature_set::stake_program_v2::id())?;
|
|
||||||
Ok(feature::from_account(&feature_account)
|
|
||||||
.and_then(|feature| feature.activated_at)
|
|
||||||
.is_some())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
@ -39,8 +39,6 @@ use solana_runtime::{
|
|||||||
use solana_sdk::{
|
use solana_sdk::{
|
||||||
account::{AccountSharedData, ReadableAccount, WritableAccount},
|
account::{AccountSharedData, ReadableAccount, WritableAccount},
|
||||||
clock::{Epoch, Slot},
|
clock::{Epoch, Slot},
|
||||||
feature::{self, Feature},
|
|
||||||
feature_set,
|
|
||||||
genesis_config::{ClusterType, GenesisConfig},
|
genesis_config::{ClusterType, GenesisConfig},
|
||||||
hash::Hash,
|
hash::Hash,
|
||||||
inflation::Inflation,
|
inflation::Inflation,
|
||||||
@ -1383,14 +1381,6 @@ fn main() {
|
|||||||
.possible_values(&["pico", "full", "none"])
|
.possible_values(&["pico", "full", "none"])
|
||||||
.help("Overwrite inflation when warping"),
|
.help("Overwrite inflation when warping"),
|
||||||
)
|
)
|
||||||
.arg(
|
|
||||||
Arg::with_name("enable_stake_program_v2")
|
|
||||||
.required(false)
|
|
||||||
.long("enable-stake-program-v2")
|
|
||||||
.takes_value(false)
|
|
||||||
.help("Enable stake program v2 (several inflation-related staking \
|
|
||||||
bugs are feature-gated behind this)"),
|
|
||||||
)
|
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("recalculate_capitalization")
|
Arg::with_name("recalculate_capitalization")
|
||||||
.required(false)
|
.required(false)
|
||||||
@ -2406,95 +2396,6 @@ fn main() {
|
|||||||
.lazy_rent_collection
|
.lazy_rent_collection
|
||||||
.store(true, std::sync::atomic::Ordering::Relaxed);
|
.store(true, std::sync::atomic::Ordering::Relaxed);
|
||||||
|
|
||||||
let feature_account_balance = std::cmp::max(
|
|
||||||
genesis_config.rent.minimum_balance(Feature::size_of()),
|
|
||||||
1,
|
|
||||||
);
|
|
||||||
if arg_matches.is_present("enable_stake_program_v2") {
|
|
||||||
let mut force_enabled_count = 0;
|
|
||||||
if base_bank
|
|
||||||
.get_account(&feature_set::stake_program_v2::id())
|
|
||||||
.is_none()
|
|
||||||
{
|
|
||||||
base_bank.store_account(
|
|
||||||
&feature_set::stake_program_v2::id(),
|
|
||||||
&feature::create_account(
|
|
||||||
&Feature { activated_at: None },
|
|
||||||
feature_account_balance,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
force_enabled_count += 1;
|
|
||||||
}
|
|
||||||
if base_bank
|
|
||||||
.get_account(&feature_set::rewrite_stake::id())
|
|
||||||
.is_none()
|
|
||||||
{
|
|
||||||
base_bank.store_account(
|
|
||||||
&feature_set::rewrite_stake::id(),
|
|
||||||
&feature::create_account(
|
|
||||||
&Feature { activated_at: None },
|
|
||||||
feature_account_balance,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
force_enabled_count += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if force_enabled_count == 0 {
|
|
||||||
warn!("Already stake_program_v2 is activated (or scheduled)");
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut store_failed_count = 0;
|
|
||||||
if force_enabled_count >= 1 {
|
|
||||||
if base_bank
|
|
||||||
.get_account(&feature_set::spl_token_v2_multisig_fix::id())
|
|
||||||
.is_some()
|
|
||||||
{
|
|
||||||
// steal some lamports from the pretty old feature not to affect
|
|
||||||
// capitalizaion, which doesn't affect inflation behavior!
|
|
||||||
base_bank.store_account(
|
|
||||||
&feature_set::spl_token_v2_multisig_fix::id(),
|
|
||||||
&AccountSharedData::default(),
|
|
||||||
);
|
|
||||||
force_enabled_count -= 1;
|
|
||||||
} else {
|
|
||||||
store_failed_count += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if force_enabled_count >= 1 {
|
|
||||||
if base_bank
|
|
||||||
.get_account(&feature_set::instructions_sysvar_enabled::id())
|
|
||||||
.is_some()
|
|
||||||
{
|
|
||||||
// steal some lamports from the pretty old feature not to affect
|
|
||||||
// capitalizaion, which doesn't affect inflation behavior!
|
|
||||||
base_bank.store_account(
|
|
||||||
&feature_set::instructions_sysvar_enabled::id(),
|
|
||||||
&AccountSharedData::default(),
|
|
||||||
);
|
|
||||||
force_enabled_count -= 1;
|
|
||||||
} else {
|
|
||||||
store_failed_count += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
assert_eq!(force_enabled_count, store_failed_count);
|
|
||||||
if store_failed_count >= 1 {
|
|
||||||
// we have no choice; maybe locally created blank cluster with
|
|
||||||
// not-Development cluster type.
|
|
||||||
let old_cap = base_bank.set_capitalization();
|
|
||||||
let new_cap = base_bank.capitalization();
|
|
||||||
warn!(
|
|
||||||
"Skewing capitalization a bit to enable stake_program_v2 as \
|
|
||||||
requested: increasing {} from {} to {}",
|
|
||||||
feature_account_balance, old_cap, new_cap,
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
old_cap + feature_account_balance * store_failed_count,
|
|
||||||
new_cap
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Default, Debug)]
|
#[derive(Default, Debug)]
|
||||||
struct PointDetail {
|
struct PointDetail {
|
||||||
epoch: Epoch,
|
epoch: Epoch,
|
||||||
|
@ -277,7 +277,7 @@ async fn stake_rewards_from_warp() {
|
|||||||
assert_matches!(
|
assert_matches!(
|
||||||
stake
|
stake
|
||||||
.delegation
|
.delegation
|
||||||
.stake_activating_and_deactivating(clock.epoch, Some(&stake_history), true,),
|
.stake_activating_and_deactivating(clock.epoch, Some(&stake_history)),
|
||||||
(_, 0, 0)
|
(_, 0, 0)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -99,7 +99,7 @@ fn redelegate(
|
|||||||
can_reverse_deactivation: bool,
|
can_reverse_deactivation: bool,
|
||||||
) -> Result<(), StakeError> {
|
) -> Result<(), StakeError> {
|
||||||
// If stake is currently active:
|
// If stake is currently active:
|
||||||
if stake.stake(clock.epoch, Some(stake_history), true) != 0 {
|
if stake.stake(clock.epoch, Some(stake_history)) != 0 {
|
||||||
// If pubkey of new voter is the same as current,
|
// If pubkey of new voter is the same as current,
|
||||||
// and we are scheduled to start deactivating this epoch,
|
// and we are scheduled to start deactivating this epoch,
|
||||||
// we rescind deactivation
|
// we rescind deactivation
|
||||||
@ -161,7 +161,6 @@ fn redeem_stake_rewards(
|
|||||||
vote_state: &VoteState,
|
vote_state: &VoteState,
|
||||||
stake_history: Option<&StakeHistory>,
|
stake_history: Option<&StakeHistory>,
|
||||||
inflation_point_calc_tracer: &mut Option<impl FnMut(&InflationPointCalculationEvent)>,
|
inflation_point_calc_tracer: &mut Option<impl FnMut(&InflationPointCalculationEvent)>,
|
||||||
fix_stake_deactivate: bool,
|
|
||||||
) -> Option<(u64, u64)> {
|
) -> Option<(u64, u64)> {
|
||||||
if let Some(inflation_point_calc_tracer) = inflation_point_calc_tracer {
|
if let Some(inflation_point_calc_tracer) = inflation_point_calc_tracer {
|
||||||
inflation_point_calc_tracer(&InflationPointCalculationEvent::CreditsObserved(
|
inflation_point_calc_tracer(&InflationPointCalculationEvent::CreditsObserved(
|
||||||
@ -175,7 +174,6 @@ fn redeem_stake_rewards(
|
|||||||
vote_state,
|
vote_state,
|
||||||
stake_history,
|
stake_history,
|
||||||
inflation_point_calc_tracer,
|
inflation_point_calc_tracer,
|
||||||
fix_stake_deactivate,
|
|
||||||
)
|
)
|
||||||
.map(|(stakers_reward, voters_reward, credits_observed)| {
|
.map(|(stakers_reward, voters_reward, credits_observed)| {
|
||||||
if let Some(inflation_point_calc_tracer) = inflation_point_calc_tracer {
|
if let Some(inflation_point_calc_tracer) = inflation_point_calc_tracer {
|
||||||
@ -195,14 +193,12 @@ fn calculate_stake_points(
|
|||||||
vote_state: &VoteState,
|
vote_state: &VoteState,
|
||||||
stake_history: Option<&StakeHistory>,
|
stake_history: Option<&StakeHistory>,
|
||||||
inflation_point_calc_tracer: &mut Option<impl FnMut(&InflationPointCalculationEvent)>,
|
inflation_point_calc_tracer: &mut Option<impl FnMut(&InflationPointCalculationEvent)>,
|
||||||
fix_stake_deactivate: bool,
|
|
||||||
) -> u128 {
|
) -> u128 {
|
||||||
calculate_stake_points_and_credits(
|
calculate_stake_points_and_credits(
|
||||||
stake,
|
stake,
|
||||||
vote_state,
|
vote_state,
|
||||||
stake_history,
|
stake_history,
|
||||||
inflation_point_calc_tracer,
|
inflation_point_calc_tracer,
|
||||||
fix_stake_deactivate,
|
|
||||||
)
|
)
|
||||||
.0
|
.0
|
||||||
}
|
}
|
||||||
@ -215,21 +211,13 @@ fn calculate_stake_points_and_credits(
|
|||||||
new_vote_state: &VoteState,
|
new_vote_state: &VoteState,
|
||||||
stake_history: Option<&StakeHistory>,
|
stake_history: Option<&StakeHistory>,
|
||||||
inflation_point_calc_tracer: &mut Option<impl FnMut(&InflationPointCalculationEvent)>,
|
inflation_point_calc_tracer: &mut Option<impl FnMut(&InflationPointCalculationEvent)>,
|
||||||
fix_stake_deactivate: bool,
|
|
||||||
) -> (u128, u64) {
|
) -> (u128, u64) {
|
||||||
// if there is no newer credits since observed, return no point
|
// if there is no newer credits since observed, return no point
|
||||||
if new_vote_state.credits() <= stake.credits_observed {
|
if new_vote_state.credits() <= stake.credits_observed {
|
||||||
if fix_stake_deactivate {
|
|
||||||
if let Some(inflation_point_calc_tracer) = inflation_point_calc_tracer {
|
if let Some(inflation_point_calc_tracer) = inflation_point_calc_tracer {
|
||||||
inflation_point_calc_tracer(&SkippedReason::ZeroCreditsAndReturnCurrent.into());
|
inflation_point_calc_tracer(&SkippedReason::ZeroCreditsAndReturnCurrent.into());
|
||||||
}
|
}
|
||||||
return (0, stake.credits_observed);
|
return (0, stake.credits_observed);
|
||||||
} else {
|
|
||||||
if let Some(inflation_point_calc_tracer) = inflation_point_calc_tracer {
|
|
||||||
inflation_point_calc_tracer(&SkippedReason::ZeroCreditsAndReturnZero.into());
|
|
||||||
}
|
|
||||||
return (0, 0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut points = 0;
|
let mut points = 0;
|
||||||
@ -238,11 +226,7 @@ fn calculate_stake_points_and_credits(
|
|||||||
for (epoch, final_epoch_credits, initial_epoch_credits) in
|
for (epoch, final_epoch_credits, initial_epoch_credits) in
|
||||||
new_vote_state.epoch_credits().iter().copied()
|
new_vote_state.epoch_credits().iter().copied()
|
||||||
{
|
{
|
||||||
let stake_amount = u128::from(stake.delegation.stake(
|
let stake_amount = u128::from(stake.delegation.stake(epoch, stake_history));
|
||||||
epoch,
|
|
||||||
stake_history,
|
|
||||||
fix_stake_deactivate,
|
|
||||||
));
|
|
||||||
|
|
||||||
// figure out how much this stake has seen that
|
// figure out how much this stake has seen that
|
||||||
// for which the vote account has a record
|
// for which the vote account has a record
|
||||||
@ -285,24 +269,22 @@ fn calculate_stake_points_and_credits(
|
|||||||
/// * voter_rewards to be distributed
|
/// * voter_rewards to be distributed
|
||||||
/// * new value for credits_observed in the stake
|
/// * new value for credits_observed in the stake
|
||||||
/// returns None if there's no payout or if any deserved payout is < 1 lamport
|
/// returns None if there's no payout or if any deserved payout is < 1 lamport
|
||||||
pub fn calculate_stake_rewards(
|
fn calculate_stake_rewards(
|
||||||
stake: &Stake,
|
stake: &Stake,
|
||||||
point_value: &PointValue,
|
point_value: &PointValue,
|
||||||
vote_state: &VoteState,
|
vote_state: &VoteState,
|
||||||
stake_history: Option<&StakeHistory>,
|
stake_history: Option<&StakeHistory>,
|
||||||
inflation_point_calc_tracer: &mut Option<impl FnMut(&InflationPointCalculationEvent)>,
|
inflation_point_calc_tracer: &mut Option<impl FnMut(&InflationPointCalculationEvent)>,
|
||||||
fix_stake_deactivate: bool,
|
|
||||||
) -> Option<(u64, u64, u64)> {
|
) -> Option<(u64, u64, u64)> {
|
||||||
let (points, credits_observed) = calculate_stake_points_and_credits(
|
let (points, credits_observed) = calculate_stake_points_and_credits(
|
||||||
stake,
|
stake,
|
||||||
vote_state,
|
vote_state,
|
||||||
stake_history,
|
stake_history,
|
||||||
inflation_point_calc_tracer,
|
inflation_point_calc_tracer,
|
||||||
fix_stake_deactivate,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// Drive credits_observed forward unconditionally when rewards are disabled
|
// Drive credits_observed forward unconditionally when rewards are disabled
|
||||||
if point_value.rewards == 0 && fix_stake_deactivate {
|
if point_value.rewards == 0 {
|
||||||
return Some((0, 0, credits_observed));
|
return Some((0, 0, credits_observed));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -786,9 +768,7 @@ impl<'a> StakeAccount for KeyedAccount<'a> {
|
|||||||
.check(&signers, StakeAuthorize::Withdrawer)?;
|
.check(&signers, StakeAuthorize::Withdrawer)?;
|
||||||
// if we have a deactivation epoch and we're in cooldown
|
// if we have a deactivation epoch and we're in cooldown
|
||||||
let staked = if clock.epoch >= stake.delegation.deactivation_epoch {
|
let staked = if clock.epoch >= stake.delegation.deactivation_epoch {
|
||||||
stake
|
stake.delegation.stake(clock.epoch, Some(stake_history))
|
||||||
.delegation
|
|
||||||
.stake(clock.epoch, Some(stake_history), true)
|
|
||||||
} else {
|
} else {
|
||||||
// Assume full stake if the stake account hasn't been
|
// Assume full stake if the stake account hasn't been
|
||||||
// de-activated, because in the future the exposed stake
|
// de-activated, because in the future the exposed stake
|
||||||
@ -886,11 +866,10 @@ impl MergeKind {
|
|||||||
StakeState::Stake(meta, stake) => {
|
StakeState::Stake(meta, stake) => {
|
||||||
// stake must not be in a transient state. Transient here meaning
|
// stake must not be in a transient state. Transient here meaning
|
||||||
// activating or deactivating with non-zero effective stake.
|
// activating or deactivating with non-zero effective stake.
|
||||||
match stake.delegation.stake_activating_and_deactivating(
|
match stake
|
||||||
clock.epoch,
|
.delegation
|
||||||
Some(stake_history),
|
.stake_activating_and_deactivating(clock.epoch, Some(stake_history))
|
||||||
true,
|
{
|
||||||
) {
|
|
||||||
/*
|
/*
|
||||||
(e, a, d): e - effective, a - activating, d - deactivating */
|
(e, a, d): e - effective, a - activating, d - deactivating */
|
||||||
(0, 0, 0) => Ok(Self::Inactive(meta, stake_keyed_account.lamports()?)),
|
(0, 0, 0) => Ok(Self::Inactive(meta, stake_keyed_account.lamports()?)),
|
||||||
@ -1119,16 +1098,13 @@ pub fn redeem_rewards(
|
|||||||
point_value: &PointValue,
|
point_value: &PointValue,
|
||||||
stake_history: Option<&StakeHistory>,
|
stake_history: Option<&StakeHistory>,
|
||||||
inflation_point_calc_tracer: &mut Option<impl FnMut(&InflationPointCalculationEvent)>,
|
inflation_point_calc_tracer: &mut Option<impl FnMut(&InflationPointCalculationEvent)>,
|
||||||
fix_stake_deactivate: bool,
|
|
||||||
) -> Result<(u64, u64), InstructionError> {
|
) -> Result<(u64, u64), InstructionError> {
|
||||||
if let StakeState::Stake(meta, mut stake) = stake_account.state()? {
|
if let StakeState::Stake(meta, mut stake) = stake_account.state()? {
|
||||||
if let Some(inflation_point_calc_tracer) = inflation_point_calc_tracer {
|
if let Some(inflation_point_calc_tracer) = inflation_point_calc_tracer {
|
||||||
inflation_point_calc_tracer(
|
inflation_point_calc_tracer(
|
||||||
&InflationPointCalculationEvent::EffectiveStakeAtRewardedEpoch(stake.stake(
|
&InflationPointCalculationEvent::EffectiveStakeAtRewardedEpoch(
|
||||||
rewarded_epoch,
|
stake.stake(rewarded_epoch, stake_history),
|
||||||
stake_history,
|
),
|
||||||
fix_stake_deactivate,
|
|
||||||
)),
|
|
||||||
);
|
);
|
||||||
inflation_point_calc_tracer(&InflationPointCalculationEvent::RentExemptReserve(
|
inflation_point_calc_tracer(&InflationPointCalculationEvent::RentExemptReserve(
|
||||||
meta.rent_exempt_reserve,
|
meta.rent_exempt_reserve,
|
||||||
@ -1144,7 +1120,6 @@ pub fn redeem_rewards(
|
|||||||
vote_state,
|
vote_state,
|
||||||
stake_history,
|
stake_history,
|
||||||
inflation_point_calc_tracer,
|
inflation_point_calc_tracer,
|
||||||
fix_stake_deactivate,
|
|
||||||
) {
|
) {
|
||||||
stake_account.checked_add_lamports(stakers_reward)?;
|
stake_account.checked_add_lamports(stakers_reward)?;
|
||||||
vote_account.checked_add_lamports(voters_reward)?;
|
vote_account.checked_add_lamports(voters_reward)?;
|
||||||
@ -1165,7 +1140,6 @@ pub fn calculate_points(
|
|||||||
stake_account: &AccountSharedData,
|
stake_account: &AccountSharedData,
|
||||||
vote_account: &AccountSharedData,
|
vote_account: &AccountSharedData,
|
||||||
stake_history: Option<&StakeHistory>,
|
stake_history: Option<&StakeHistory>,
|
||||||
fix_stake_deactivate: bool,
|
|
||||||
) -> Result<u128, InstructionError> {
|
) -> Result<u128, InstructionError> {
|
||||||
if let StakeState::Stake(_meta, stake) = stake_account.state()? {
|
if let StakeState::Stake(_meta, stake) = stake_account.state()? {
|
||||||
let vote_state: VoteState =
|
let vote_state: VoteState =
|
||||||
@ -1176,7 +1150,6 @@ pub fn calculate_points(
|
|||||||
&vote_state,
|
&vote_state,
|
||||||
stake_history,
|
stake_history,
|
||||||
&mut null_tracer(),
|
&mut null_tracer(),
|
||||||
fix_stake_deactivate,
|
|
||||||
))
|
))
|
||||||
} else {
|
} else {
|
||||||
Err(InstructionError::InvalidAccountData)
|
Err(InstructionError::InvalidAccountData)
|
||||||
@ -1198,48 +1171,11 @@ fn calculate_split_rent_exempt_reserve(
|
|||||||
|
|
||||||
pub type RewriteStakeStatus = (&'static str, (u64, u64), (u64, u64));
|
pub type RewriteStakeStatus = (&'static str, (u64, u64), (u64, u64));
|
||||||
|
|
||||||
pub fn rewrite_stakes(
|
|
||||||
stake_account: &mut AccountSharedData,
|
|
||||||
rent: &Rent,
|
|
||||||
) -> Result<RewriteStakeStatus, InstructionError> {
|
|
||||||
match stake_account.state()? {
|
|
||||||
StakeState::Initialized(mut meta) => {
|
|
||||||
let meta_status = meta.rewrite_rent_exempt_reserve(rent, stake_account.data().len());
|
|
||||||
|
|
||||||
if meta_status.is_none() {
|
|
||||||
return Err(InstructionError::InvalidAccountData);
|
|
||||||
}
|
|
||||||
|
|
||||||
stake_account.set_state(&StakeState::Initialized(meta))?;
|
|
||||||
Ok(("initialized", meta_status.unwrap_or_default(), (0, 0)))
|
|
||||||
}
|
|
||||||
StakeState::Stake(mut meta, mut stake) => {
|
|
||||||
let meta_status = meta.rewrite_rent_exempt_reserve(rent, stake_account.data().len());
|
|
||||||
let stake_status = stake
|
|
||||||
.delegation
|
|
||||||
.rewrite_stake(stake_account.lamports(), meta.rent_exempt_reserve);
|
|
||||||
|
|
||||||
if meta_status.is_none() && stake_status.is_none() {
|
|
||||||
return Err(InstructionError::InvalidAccountData);
|
|
||||||
}
|
|
||||||
|
|
||||||
stake_account.set_state(&StakeState::Stake(meta, stake))?;
|
|
||||||
Ok((
|
|
||||||
"stake",
|
|
||||||
meta_status.unwrap_or_default(),
|
|
||||||
stake_status.unwrap_or_default(),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
_ => Err(InstructionError::InvalidAccountData),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// utility function, used by runtime::Stakes, tests
|
// utility function, used by runtime::Stakes, tests
|
||||||
pub fn new_stake_history_entry<'a, I>(
|
pub fn new_stake_history_entry<'a, I>(
|
||||||
epoch: Epoch,
|
epoch: Epoch,
|
||||||
stakes: I,
|
stakes: I,
|
||||||
history: Option<&StakeHistory>,
|
history: Option<&StakeHistory>,
|
||||||
fix_stake_deactivate: bool,
|
|
||||||
) -> StakeHistoryEntry
|
) -> StakeHistoryEntry
|
||||||
where
|
where
|
||||||
I: Iterator<Item = &'a Delegation>,
|
I: Iterator<Item = &'a Delegation>,
|
||||||
@ -1250,10 +1186,7 @@ where
|
|||||||
(a.0 + b.0, a.1 + b.1, a.2 + b.2)
|
(a.0 + b.0, a.1 + b.1, a.2 + b.2)
|
||||||
}
|
}
|
||||||
let (effective, activating, deactivating) = stakes.fold((0, 0, 0), |sum, stake| {
|
let (effective, activating, deactivating) = stakes.fold((0, 0, 0), |sum, stake| {
|
||||||
add(
|
add(sum, stake.stake_activating_and_deactivating(epoch, history))
|
||||||
sum,
|
|
||||||
stake.stake_activating_and_deactivating(epoch, history, fix_stake_deactivate),
|
|
||||||
)
|
|
||||||
});
|
});
|
||||||
|
|
||||||
StakeHistoryEntry {
|
StakeHistoryEntry {
|
||||||
@ -1801,7 +1734,6 @@ mod tests {
|
|||||||
epoch,
|
epoch,
|
||||||
delegations.iter().chain(bootstrap_delegation.iter()),
|
delegations.iter().chain(bootstrap_delegation.iter()),
|
||||||
Some(&stake_history),
|
Some(&stake_history),
|
||||||
true,
|
|
||||||
);
|
);
|
||||||
stake_history.add(epoch, entry);
|
stake_history.add(epoch, entry);
|
||||||
}
|
}
|
||||||
@ -1824,26 +1756,19 @@ mod tests {
|
|||||||
let mut stake_history = StakeHistory::default();
|
let mut stake_history = StakeHistory::default();
|
||||||
// assert that this stake follows step function if there's no history
|
// assert that this stake follows step function if there's no history
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
stake.stake_activating_and_deactivating(
|
stake.stake_activating_and_deactivating(stake.activation_epoch, Some(&stake_history),),
|
||||||
stake.activation_epoch,
|
|
||||||
Some(&stake_history),
|
|
||||||
true
|
|
||||||
),
|
|
||||||
(0, stake.stake, 0)
|
(0, stake.stake, 0)
|
||||||
);
|
);
|
||||||
for epoch in stake.activation_epoch + 1..stake.deactivation_epoch {
|
for epoch in stake.activation_epoch + 1..stake.deactivation_epoch {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
stake.stake_activating_and_deactivating(epoch, Some(&stake_history), true),
|
stake.stake_activating_and_deactivating(epoch, Some(&stake_history)),
|
||||||
(stake.stake, 0, 0)
|
(stake.stake, 0, 0)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
// assert that this stake is full deactivating
|
// assert that this stake is full deactivating
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
stake.stake_activating_and_deactivating(
|
stake
|
||||||
stake.deactivation_epoch,
|
.stake_activating_and_deactivating(stake.deactivation_epoch, Some(&stake_history),),
|
||||||
Some(&stake_history),
|
|
||||||
true
|
|
||||||
),
|
|
||||||
(stake.stake, 0, stake.stake)
|
(stake.stake, 0, stake.stake)
|
||||||
);
|
);
|
||||||
// assert that this stake is fully deactivated if there's no history
|
// assert that this stake is fully deactivated if there's no history
|
||||||
@ -1851,7 +1776,6 @@ mod tests {
|
|||||||
stake.stake_activating_and_deactivating(
|
stake.stake_activating_and_deactivating(
|
||||||
stake.deactivation_epoch + 1,
|
stake.deactivation_epoch + 1,
|
||||||
Some(&stake_history),
|
Some(&stake_history),
|
||||||
true,
|
|
||||||
),
|
),
|
||||||
(0, 0, 0)
|
(0, 0, 0)
|
||||||
);
|
);
|
||||||
@ -1866,7 +1790,7 @@ mod tests {
|
|||||||
);
|
);
|
||||||
// assert that this stake is broken, because above setup is broken
|
// assert that this stake is broken, because above setup is broken
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
stake.stake_activating_and_deactivating(1, Some(&stake_history), true),
|
stake.stake_activating_and_deactivating(1, Some(&stake_history)),
|
||||||
(0, stake.stake, 0)
|
(0, stake.stake, 0)
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -1881,7 +1805,7 @@ mod tests {
|
|||||||
);
|
);
|
||||||
// assert that this stake is broken, because above setup is broken
|
// assert that this stake is broken, because above setup is broken
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
stake.stake_activating_and_deactivating(2, Some(&stake_history), true),
|
stake.stake_activating_and_deactivating(2, Some(&stake_history)),
|
||||||
(increment, stake.stake - increment, 0)
|
(increment, stake.stake - increment, 0)
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -1901,7 +1825,6 @@ mod tests {
|
|||||||
stake.stake_activating_and_deactivating(
|
stake.stake_activating_and_deactivating(
|
||||||
stake.deactivation_epoch + 1,
|
stake.deactivation_epoch + 1,
|
||||||
Some(&stake_history),
|
Some(&stake_history),
|
||||||
true,
|
|
||||||
),
|
),
|
||||||
(stake.stake, 0, stake.stake) // says "I'm still waiting for deactivation"
|
(stake.stake, 0, stake.stake) // says "I'm still waiting for deactivation"
|
||||||
);
|
);
|
||||||
@ -1920,7 +1843,6 @@ mod tests {
|
|||||||
stake.stake_activating_and_deactivating(
|
stake.stake_activating_and_deactivating(
|
||||||
stake.deactivation_epoch + 2,
|
stake.deactivation_epoch + 2,
|
||||||
Some(&stake_history),
|
Some(&stake_history),
|
||||||
true,
|
|
||||||
),
|
),
|
||||||
(stake.stake - increment, 0, stake.stake - increment) // hung, should be lower
|
(stake.stake - increment, 0, stake.stake - increment) // hung, should be lower
|
||||||
);
|
);
|
||||||
@ -1934,11 +1856,7 @@ mod tests {
|
|||||||
Slow,
|
Slow,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn do_test(
|
fn do_test(old_behavior: OldDeactivationBehavior, expected_stakes: &[(u64, u64, u64)]) {
|
||||||
old_behavior: OldDeactivationBehavior,
|
|
||||||
fix_stake_deactivate: bool,
|
|
||||||
expected_stakes: &[(u64, u64, u64)],
|
|
||||||
) {
|
|
||||||
let cluster_stake = 1_000;
|
let cluster_stake = 1_000;
|
||||||
let activating_stake = 10_000;
|
let activating_stake = 10_000;
|
||||||
let some_stake = 700;
|
let some_stake = 700;
|
||||||
@ -1987,49 +1905,12 @@ mod tests {
|
|||||||
assert_eq!(
|
assert_eq!(
|
||||||
expected_stakes,
|
expected_stakes,
|
||||||
(0..expected_stakes.len())
|
(0..expected_stakes.len())
|
||||||
.map(|epoch| stake.stake_activating_and_deactivating(
|
.map(|epoch| stake
|
||||||
epoch as u64,
|
.stake_activating_and_deactivating(epoch as u64, Some(&stake_history),))
|
||||||
Some(&stake_history),
|
|
||||||
fix_stake_deactivate
|
|
||||||
))
|
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_old_behavior_slow() {
|
|
||||||
do_test(
|
|
||||||
OldDeactivationBehavior::Slow,
|
|
||||||
false,
|
|
||||||
&[
|
|
||||||
(0, 0, 0),
|
|
||||||
(13, 0, 13),
|
|
||||||
(10, 0, 10),
|
|
||||||
(8, 0, 8),
|
|
||||||
(0, 0, 0),
|
|
||||||
(0, 0, 0),
|
|
||||||
(0, 0, 0),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_old_behavior_stuck() {
|
|
||||||
do_test(
|
|
||||||
OldDeactivationBehavior::Stuck,
|
|
||||||
false,
|
|
||||||
&[
|
|
||||||
(0, 0, 0),
|
|
||||||
(17, 0, 17),
|
|
||||||
(17, 0, 17),
|
|
||||||
(17, 0, 17),
|
|
||||||
(17, 0, 17),
|
|
||||||
(17, 0, 17),
|
|
||||||
(17, 0, 17),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_new_behavior_previously_slow() {
|
fn test_new_behavior_previously_slow() {
|
||||||
// any stake accounts activated and deactivated at the same epoch
|
// any stake accounts activated and deactivated at the same epoch
|
||||||
@ -2037,7 +1918,6 @@ mod tests {
|
|||||||
|
|
||||||
do_test(
|
do_test(
|
||||||
OldDeactivationBehavior::Slow,
|
OldDeactivationBehavior::Slow,
|
||||||
true,
|
|
||||||
&[
|
&[
|
||||||
(0, 0, 0),
|
(0, 0, 0),
|
||||||
(0, 0, 0),
|
(0, 0, 0),
|
||||||
@ -2057,7 +1937,6 @@ mod tests {
|
|||||||
|
|
||||||
do_test(
|
do_test(
|
||||||
OldDeactivationBehavior::Stuck,
|
OldDeactivationBehavior::Stuck,
|
||||||
true,
|
|
||||||
&[
|
&[
|
||||||
(0, 0, 0),
|
(0, 0, 0),
|
||||||
(0, 0, 0),
|
(0, 0, 0),
|
||||||
@ -2154,11 +2033,7 @@ mod tests {
|
|||||||
let calculate_each_staking_status = |stake: &Delegation, epoch_count: usize| -> Vec<_> {
|
let calculate_each_staking_status = |stake: &Delegation, epoch_count: usize| -> Vec<_> {
|
||||||
(0..epoch_count)
|
(0..epoch_count)
|
||||||
.map(|epoch| {
|
.map(|epoch| {
|
||||||
stake.stake_activating_and_deactivating(
|
stake.stake_activating_and_deactivating(epoch as u64, Some(&stake_history))
|
||||||
epoch as u64,
|
|
||||||
Some(&stake_history),
|
|
||||||
true,
|
|
||||||
)
|
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
};
|
};
|
||||||
@ -2282,7 +2157,7 @@ mod tests {
|
|||||||
(0, history.deactivating)
|
(0, history.deactivating)
|
||||||
};
|
};
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
stake.stake_activating_and_deactivating(epoch, Some(&stake_history), true),
|
stake.stake_activating_and_deactivating(epoch, Some(&stake_history)),
|
||||||
(expected_stake, expected_activating, expected_deactivating)
|
(expected_stake, expected_activating, expected_deactivating)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -2309,7 +2184,7 @@ mod tests {
|
|||||||
for epoch in 0..epochs {
|
for epoch in 0..epochs {
|
||||||
let stake = delegations
|
let stake = delegations
|
||||||
.iter()
|
.iter()
|
||||||
.map(|delegation| delegation.stake(epoch, Some(&stake_history), true))
|
.map(|delegation| delegation.stake(epoch, Some(&stake_history)))
|
||||||
.sum::<u64>();
|
.sum::<u64>();
|
||||||
max_stake = max_stake.max(stake);
|
max_stake = max_stake.max(stake);
|
||||||
min_stake = min_stake.min(stake);
|
min_stake = min_stake.min(stake);
|
||||||
@ -2368,7 +2243,7 @@ mod tests {
|
|||||||
|
|
||||||
let mut prev_total_effective_stake = delegations
|
let mut prev_total_effective_stake = delegations
|
||||||
.iter()
|
.iter()
|
||||||
.map(|delegation| delegation.stake(0, Some(&stake_history), true))
|
.map(|delegation| delegation.stake(0, Some(&stake_history)))
|
||||||
.sum::<u64>();
|
.sum::<u64>();
|
||||||
|
|
||||||
// uncomment and add ! for fun with graphing
|
// uncomment and add ! for fun with graphing
|
||||||
@ -2376,7 +2251,7 @@ mod tests {
|
|||||||
for epoch in 1..epochs {
|
for epoch in 1..epochs {
|
||||||
let total_effective_stake = delegations
|
let total_effective_stake = delegations
|
||||||
.iter()
|
.iter()
|
||||||
.map(|delegation| delegation.stake(epoch, Some(&stake_history), true))
|
.map(|delegation| delegation.stake(epoch, Some(&stake_history)))
|
||||||
.sum::<u64>();
|
.sum::<u64>();
|
||||||
|
|
||||||
let delta = if total_effective_stake > prev_total_effective_stake {
|
let delta = if total_effective_stake > prev_total_effective_stake {
|
||||||
@ -3512,7 +3387,6 @@ mod tests {
|
|||||||
&vote_state,
|
&vote_state,
|
||||||
None,
|
None,
|
||||||
&mut null_tracer(),
|
&mut null_tracer(),
|
||||||
true,
|
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -3532,7 +3406,6 @@ mod tests {
|
|||||||
&vote_state,
|
&vote_state,
|
||||||
None,
|
None,
|
||||||
&mut null_tracer(),
|
&mut null_tracer(),
|
||||||
true,
|
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -3569,7 +3442,6 @@ mod tests {
|
|||||||
&vote_state,
|
&vote_state,
|
||||||
None,
|
None,
|
||||||
&mut null_tracer(),
|
&mut null_tracer(),
|
||||||
true,
|
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -3583,7 +3455,7 @@ mod tests {
|
|||||||
// no overflow on points
|
// no overflow on points
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
u128::from(stake.delegation.stake) * epoch_slots,
|
u128::from(stake.delegation.stake) * epoch_slots,
|
||||||
calculate_stake_points(&stake, &vote_state, None, &mut null_tracer(), true)
|
calculate_stake_points(&stake, &vote_state, None, &mut null_tracer())
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3612,7 +3484,6 @@ mod tests {
|
|||||||
&vote_state,
|
&vote_state,
|
||||||
None,
|
None,
|
||||||
&mut null_tracer(),
|
&mut null_tracer(),
|
||||||
true,
|
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -3632,7 +3503,6 @@ mod tests {
|
|||||||
&vote_state,
|
&vote_state,
|
||||||
None,
|
None,
|
||||||
&mut null_tracer(),
|
&mut null_tracer(),
|
||||||
true,
|
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -3649,7 +3519,6 @@ mod tests {
|
|||||||
&vote_state,
|
&vote_state,
|
||||||
None,
|
None,
|
||||||
&mut null_tracer(),
|
&mut null_tracer(),
|
||||||
true,
|
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -3669,7 +3538,6 @@ mod tests {
|
|||||||
&vote_state,
|
&vote_state,
|
||||||
None,
|
None,
|
||||||
&mut null_tracer(),
|
&mut null_tracer(),
|
||||||
true,
|
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -3687,7 +3555,6 @@ mod tests {
|
|||||||
&vote_state,
|
&vote_state,
|
||||||
None,
|
None,
|
||||||
&mut null_tracer(),
|
&mut null_tracer(),
|
||||||
true,
|
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -3711,7 +3578,6 @@ mod tests {
|
|||||||
&vote_state,
|
&vote_state,
|
||||||
None,
|
None,
|
||||||
&mut null_tracer(),
|
&mut null_tracer(),
|
||||||
true,
|
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -3729,7 +3595,6 @@ mod tests {
|
|||||||
&vote_state,
|
&vote_state,
|
||||||
None,
|
None,
|
||||||
&mut null_tracer(),
|
&mut null_tracer(),
|
||||||
true,
|
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
vote_state.commission = 99;
|
vote_state.commission = 99;
|
||||||
@ -3744,7 +3609,6 @@ mod tests {
|
|||||||
&vote_state,
|
&vote_state,
|
||||||
None,
|
None,
|
||||||
&mut null_tracer(),
|
&mut null_tracer(),
|
||||||
true,
|
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -3762,7 +3626,6 @@ mod tests {
|
|||||||
&vote_state,
|
&vote_state,
|
||||||
None,
|
None,
|
||||||
&mut null_tracer(),
|
&mut null_tracer(),
|
||||||
true,
|
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -3780,24 +3643,13 @@ mod tests {
|
|||||||
&vote_state,
|
&vote_state,
|
||||||
None,
|
None,
|
||||||
&mut null_tracer(),
|
&mut null_tracer(),
|
||||||
true,
|
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
// assert the previous behavior is preserved where fix_stake_deactivate=false
|
// assert the previous behavior is preserved where fix_stake_deactivate=false
|
||||||
assert_eq!(
|
|
||||||
(0, 0),
|
|
||||||
calculate_stake_points_and_credits(
|
|
||||||
&stake,
|
|
||||||
&vote_state,
|
|
||||||
None,
|
|
||||||
&mut null_tracer(),
|
|
||||||
false
|
|
||||||
)
|
|
||||||
);
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
(0, 4),
|
(0, 4),
|
||||||
calculate_stake_points_and_credits(&stake, &vote_state, None, &mut null_tracer(), true)
|
calculate_stake_points_and_credits(&stake, &vote_state, None, &mut null_tracer())
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5520,8 +5372,8 @@ mod tests {
|
|||||||
deactivating,
|
deactivating,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
if stake_amount == stake.stake(clock.epoch, Some(&stake_history), true)
|
if stake_amount == stake.stake(clock.epoch, Some(&stake_history))
|
||||||
&& source_amount == source_stake.stake(clock.epoch, Some(&stake_history), true)
|
&& source_amount == source_stake.stake(clock.epoch, Some(&stake_history))
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -5606,8 +5458,8 @@ mod tests {
|
|||||||
deactivating,
|
deactivating,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
if 0 == stake.stake(clock.epoch, Some(&stake_history), true)
|
if 0 == stake.stake(clock.epoch, Some(&stake_history))
|
||||||
&& 0 == source_stake.stake(clock.epoch, Some(&stake_history), true)
|
&& 0 == source_stake.stake(clock.epoch, Some(&stake_history))
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -5968,98 +5820,6 @@ mod tests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_stake_rewrite_stake() {
|
|
||||||
let right_data_len = std::mem::size_of::<StakeState>() as u64;
|
|
||||||
let rent = Rent::default();
|
|
||||||
let rent_exempt_reserve = rent.minimum_balance(right_data_len as usize);
|
|
||||||
let expected_stake = 1000;
|
|
||||||
let account_balance = rent_exempt_reserve + expected_stake;
|
|
||||||
|
|
||||||
let test_cases = [
|
|
||||||
(9999, Some((9999, expected_stake))), // large stake
|
|
||||||
(1000, None), // correct
|
|
||||||
(42, Some((42, expected_stake))), // small stake
|
|
||||||
];
|
|
||||||
for (staked_amount, expected_rewrite) in &test_cases {
|
|
||||||
let mut delegation = Delegation {
|
|
||||||
stake: *staked_amount,
|
|
||||||
..Delegation::default()
|
|
||||||
};
|
|
||||||
let actual_rewrite = delegation.rewrite_stake(account_balance, rent_exempt_reserve);
|
|
||||||
assert_eq!(actual_rewrite, *expected_rewrite);
|
|
||||||
assert_eq!(delegation.stake, expected_stake);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
enum ExpectedRewriteResult {
|
|
||||||
NotRewritten,
|
|
||||||
Rewritten,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_rewrite_stakes_initialized() {
|
|
||||||
let right_data_len = std::mem::size_of::<StakeState>();
|
|
||||||
let rent = Rent::default();
|
|
||||||
let rent_exempt_reserve = rent.minimum_balance(right_data_len as usize);
|
|
||||||
let expected_stake = 1000;
|
|
||||||
let account_balance = rent_exempt_reserve + expected_stake;
|
|
||||||
|
|
||||||
let test_cases = [
|
|
||||||
(1, ExpectedRewriteResult::Rewritten),
|
|
||||||
(0, ExpectedRewriteResult::NotRewritten),
|
|
||||||
];
|
|
||||||
for (offset, expected_rewrite) in &test_cases {
|
|
||||||
let meta = Meta {
|
|
||||||
rent_exempt_reserve: rent_exempt_reserve + offset,
|
|
||||||
..Meta::default()
|
|
||||||
};
|
|
||||||
let mut account = AccountSharedData::new(account_balance, right_data_len, &id());
|
|
||||||
account.set_state(&StakeState::Initialized(meta)).unwrap();
|
|
||||||
let result = rewrite_stakes(&mut account, &rent);
|
|
||||||
match expected_rewrite {
|
|
||||||
ExpectedRewriteResult::NotRewritten => assert!(result.is_err()),
|
|
||||||
ExpectedRewriteResult::Rewritten => assert!(result.is_ok()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_rewrite_stakes_stake() {
|
|
||||||
let right_data_len = std::mem::size_of::<StakeState>();
|
|
||||||
let rent = Rent::default();
|
|
||||||
let rent_exempt_reserve = rent.minimum_balance(right_data_len as usize);
|
|
||||||
let expected_stake = 1000;
|
|
||||||
let account_balance = rent_exempt_reserve + expected_stake;
|
|
||||||
|
|
||||||
let test_cases = [
|
|
||||||
(1, 9999, ExpectedRewriteResult::Rewritten), // bad meta, bad stake
|
|
||||||
(1, 1000, ExpectedRewriteResult::Rewritten), // bad meta, good stake
|
|
||||||
(0, 9999, ExpectedRewriteResult::Rewritten), // good meta, bad stake
|
|
||||||
(0, 1000, ExpectedRewriteResult::NotRewritten), // good meta, good stake
|
|
||||||
];
|
|
||||||
for (offset, staked_amount, expected_rewrite) in &test_cases {
|
|
||||||
let meta = Meta {
|
|
||||||
rent_exempt_reserve: rent_exempt_reserve + offset,
|
|
||||||
..Meta::default()
|
|
||||||
};
|
|
||||||
let stake = Stake {
|
|
||||||
delegation: (Delegation {
|
|
||||||
stake: *staked_amount,
|
|
||||||
..Delegation::default()
|
|
||||||
}),
|
|
||||||
..Stake::default()
|
|
||||||
};
|
|
||||||
let mut account = AccountSharedData::new(account_balance, right_data_len, &id());
|
|
||||||
account.set_state(&StakeState::Stake(meta, stake)).unwrap();
|
|
||||||
let result = rewrite_stakes(&mut account, &rent);
|
|
||||||
match expected_rewrite {
|
|
||||||
ExpectedRewriteResult::NotRewritten => assert!(result.is_err()),
|
|
||||||
ExpectedRewriteResult::Rewritten => assert!(result.is_ok()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_calculate_lamports_per_byte_year() {
|
fn test_calculate_lamports_per_byte_year() {
|
||||||
let rent = Rent::default();
|
let rent = Rent::default();
|
||||||
|
@ -1565,11 +1565,8 @@ impl JsonRpcRequestProcessor {
|
|||||||
solana_sdk::account::from_account::<StakeHistory, _>(&stake_history_account)
|
solana_sdk::account::from_account::<StakeHistory, _>(&stake_history_account)
|
||||||
.ok_or_else(Error::internal_error)?;
|
.ok_or_else(Error::internal_error)?;
|
||||||
|
|
||||||
let (active, activating, deactivating) = delegation.stake_activating_and_deactivating(
|
let (active, activating, deactivating) =
|
||||||
epoch,
|
delegation.stake_activating_and_deactivating(epoch, Some(&stake_history));
|
||||||
Some(&stake_history),
|
|
||||||
bank.stake_program_v2_enabled(),
|
|
||||||
);
|
|
||||||
let stake_activation_state = if deactivating > 0 {
|
let stake_activation_state = if deactivating > 0 {
|
||||||
StakeActivationState::Deactivating
|
StakeActivationState::Deactivating
|
||||||
} else if activating > 0 {
|
} else if activating > 0 {
|
||||||
|
@ -1021,8 +1021,6 @@ pub struct Bank {
|
|||||||
|
|
||||||
pub lazy_rent_collection: AtomicBool,
|
pub lazy_rent_collection: AtomicBool,
|
||||||
|
|
||||||
pub no_stake_rewrite: AtomicBool,
|
|
||||||
|
|
||||||
// this is temporary field only to remove rewards_pool entirely
|
// this is temporary field only to remove rewards_pool entirely
|
||||||
pub rewards_pool_pubkeys: Arc<HashSet<Pubkey>>,
|
pub rewards_pool_pubkeys: Arc<HashSet<Pubkey>>,
|
||||||
|
|
||||||
@ -1159,7 +1157,6 @@ impl Bank {
|
|||||||
rewards: RwLock::<Vec<(Pubkey, RewardInfo)>>::default(),
|
rewards: RwLock::<Vec<(Pubkey, RewardInfo)>>::default(),
|
||||||
cluster_type: Option::<ClusterType>::default(),
|
cluster_type: Option::<ClusterType>::default(),
|
||||||
lazy_rent_collection: AtomicBool::default(),
|
lazy_rent_collection: AtomicBool::default(),
|
||||||
no_stake_rewrite: AtomicBool::default(),
|
|
||||||
rewards_pool_pubkeys: Arc::<HashSet<Pubkey>>::default(),
|
rewards_pool_pubkeys: Arc::<HashSet<Pubkey>>::default(),
|
||||||
cached_executors: RwLock::<CowCachedExecutors>::default(),
|
cached_executors: RwLock::<CowCachedExecutors>::default(),
|
||||||
transaction_debug_keys: Option::<Arc<HashSet<Pubkey>>>::default(),
|
transaction_debug_keys: Option::<Arc<HashSet<Pubkey>>>::default(),
|
||||||
@ -1369,7 +1366,6 @@ impl Bank {
|
|||||||
rewards: RwLock::new(vec![]),
|
rewards: RwLock::new(vec![]),
|
||||||
cluster_type: parent.cluster_type,
|
cluster_type: parent.cluster_type,
|
||||||
lazy_rent_collection: AtomicBool::new(parent.lazy_rent_collection.load(Relaxed)),
|
lazy_rent_collection: AtomicBool::new(parent.lazy_rent_collection.load(Relaxed)),
|
||||||
no_stake_rewrite: AtomicBool::new(parent.no_stake_rewrite.load(Relaxed)),
|
|
||||||
rewards_pool_pubkeys: parent.rewards_pool_pubkeys.clone(),
|
rewards_pool_pubkeys: parent.rewards_pool_pubkeys.clone(),
|
||||||
cached_executors: RwLock::new(
|
cached_executors: RwLock::new(
|
||||||
(*parent.cached_executors.read().unwrap()).clone_with_epoch(epoch),
|
(*parent.cached_executors.read().unwrap()).clone_with_epoch(epoch),
|
||||||
@ -1410,11 +1406,7 @@ impl Bank {
|
|||||||
new.apply_feature_activations(false, false);
|
new.apply_feature_activations(false, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
let cloned = new
|
let cloned = new.stakes.read().unwrap().clone_with_epoch(epoch);
|
||||||
.stakes
|
|
||||||
.read()
|
|
||||||
.unwrap()
|
|
||||||
.clone_with_epoch(epoch, new.stake_program_v2_enabled());
|
|
||||||
*new.stakes.write().unwrap() = cloned;
|
*new.stakes.write().unwrap() = cloned;
|
||||||
|
|
||||||
let leader_schedule_epoch = epoch_schedule.get_leader_schedule_epoch(slot);
|
let leader_schedule_epoch = epoch_schedule.get_leader_schedule_epoch(slot);
|
||||||
@ -1524,7 +1516,6 @@ impl Bank {
|
|||||||
rewards: new(),
|
rewards: new(),
|
||||||
cluster_type: Some(genesis_config.cluster_type),
|
cluster_type: Some(genesis_config.cluster_type),
|
||||||
lazy_rent_collection: new(),
|
lazy_rent_collection: new(),
|
||||||
no_stake_rewrite: new(),
|
|
||||||
rewards_pool_pubkeys: new(),
|
rewards_pool_pubkeys: new(),
|
||||||
cached_executors: RwLock::new(CowCachedExecutors::new(Arc::new(RwLock::new(
|
cached_executors: RwLock::new(CowCachedExecutors::new(Arc::new(RwLock::new(
|
||||||
CachedExecutors::new(MAX_CACHED_EXECUTORS, fields.epoch),
|
CachedExecutors::new(MAX_CACHED_EXECUTORS, fields.epoch),
|
||||||
@ -1936,41 +1927,6 @@ impl Bank {
|
|||||||
self.epoch_schedule.get_slots_in_epoch(prev_epoch) as f64 / self.slots_per_year
|
self.epoch_schedule.get_slots_in_epoch(prev_epoch) as f64 / self.slots_per_year
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rewrite_stakes(&self) -> (usize, usize) {
|
|
||||||
let mut examined_count = 0;
|
|
||||||
let mut rewritten_count = 0;
|
|
||||||
self.cloned_stake_delegations()
|
|
||||||
.into_iter()
|
|
||||||
.for_each(|(stake_pubkey, _delegation)| {
|
|
||||||
examined_count += 1;
|
|
||||||
if let Some(mut stake_account) = self.get_account_with_fixed_root(&stake_pubkey) {
|
|
||||||
if let Ok(result) =
|
|
||||||
stake_state::rewrite_stakes(&mut stake_account, &self.rent_collector.rent)
|
|
||||||
{
|
|
||||||
self.store_account(&stake_pubkey, &stake_account);
|
|
||||||
let message = format!("rewrote stake: {}, {:?}", stake_pubkey, result);
|
|
||||||
info!("{}", message);
|
|
||||||
datapoint_info!("stake_info", ("info", message, String));
|
|
||||||
rewritten_count += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
info!(
|
|
||||||
"bank (slot: {}): rewrite_stakes: {} accounts rewritten / {} accounts examined",
|
|
||||||
self.slot(),
|
|
||||||
rewritten_count,
|
|
||||||
examined_count,
|
|
||||||
);
|
|
||||||
datapoint_info!(
|
|
||||||
"rewrite-stakes",
|
|
||||||
("examined_count", examined_count, i64),
|
|
||||||
("rewritten_count", rewritten_count, i64)
|
|
||||||
);
|
|
||||||
|
|
||||||
(examined_count, rewritten_count)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Calculates the starting-slot for inflation from the activation slot.
|
// Calculates the starting-slot for inflation from the activation slot.
|
||||||
// This method assumes that `pico_inflation` will be enabled before `full_inflation`, giving
|
// This method assumes that `pico_inflation` will be enabled before `full_inflation`, giving
|
||||||
// precedence to the latter. However, since `pico_inflation` is fixed-rate Inflation, should
|
// precedence to the latter. However, since `pico_inflation` is fixed-rate Inflation, should
|
||||||
@ -2037,12 +1993,8 @@ impl Bank {
|
|||||||
|
|
||||||
let old_vote_balance_and_staked = self.stakes.read().unwrap().vote_balance_and_staked();
|
let old_vote_balance_and_staked = self.stakes.read().unwrap().vote_balance_and_staked();
|
||||||
|
|
||||||
let validator_point_value = self.pay_validator_rewards(
|
let validator_point_value =
|
||||||
prev_epoch,
|
self.pay_validator_rewards(prev_epoch, validator_rewards, reward_calc_tracer);
|
||||||
validator_rewards,
|
|
||||||
reward_calc_tracer,
|
|
||||||
self.stake_program_v2_enabled(),
|
|
||||||
);
|
|
||||||
|
|
||||||
if !self
|
if !self
|
||||||
.feature_set
|
.feature_set
|
||||||
@ -2179,7 +2131,6 @@ impl Bank {
|
|||||||
rewarded_epoch: Epoch,
|
rewarded_epoch: Epoch,
|
||||||
rewards: u64,
|
rewards: u64,
|
||||||
reward_calc_tracer: &mut Option<impl FnMut(&RewardCalculationEvent)>,
|
reward_calc_tracer: &mut Option<impl FnMut(&RewardCalculationEvent)>,
|
||||||
fix_stake_deactivate: bool,
|
|
||||||
) -> f64 {
|
) -> f64 {
|
||||||
let stake_history = self.stakes.read().unwrap().history().clone();
|
let stake_history = self.stakes.read().unwrap().history().clone();
|
||||||
|
|
||||||
@ -2193,12 +2144,7 @@ impl Bank {
|
|||||||
.map(move |(_stake_pubkey, stake_account)| (stake_account, vote_account))
|
.map(move |(_stake_pubkey, stake_account)| (stake_account, vote_account))
|
||||||
})
|
})
|
||||||
.map(|(stake_account, vote_account)| {
|
.map(|(stake_account, vote_account)| {
|
||||||
stake_state::calculate_points(
|
stake_state::calculate_points(stake_account, vote_account, Some(&stake_history))
|
||||||
stake_account,
|
|
||||||
vote_account,
|
|
||||||
Some(&stake_history),
|
|
||||||
fix_stake_deactivate,
|
|
||||||
)
|
|
||||||
.unwrap_or(0)
|
.unwrap_or(0)
|
||||||
})
|
})
|
||||||
.sum();
|
.sum();
|
||||||
@ -2243,7 +2189,6 @@ impl Bank {
|
|||||||
&point_value,
|
&point_value,
|
||||||
Some(&stake_history),
|
Some(&stake_history),
|
||||||
&mut reward_calc_tracer.as_mut(),
|
&mut reward_calc_tracer.as_mut(),
|
||||||
fix_stake_deactivate,
|
|
||||||
);
|
);
|
||||||
if let Ok((stakers_reward, _voters_reward)) = redeemed {
|
if let Ok((stakers_reward, _voters_reward)) = redeemed {
|
||||||
self.store_account(stake_pubkey, stake_account);
|
self.store_account(stake_pubkey, stake_account);
|
||||||
@ -3961,7 +3906,6 @@ impl Bank {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
fn restore_old_behavior_for_fragile_tests(&self) {
|
fn restore_old_behavior_for_fragile_tests(&self) {
|
||||||
self.lazy_rent_collection.store(true, Relaxed);
|
self.lazy_rent_collection.store(true, Relaxed);
|
||||||
self.no_stake_rewrite.store(true, Relaxed);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn enable_eager_rent_collection(&self) -> bool {
|
fn enable_eager_rent_collection(&self) -> bool {
|
||||||
@ -4513,7 +4457,6 @@ impl Bank {
|
|||||||
self.stakes.write().unwrap().store(
|
self.stakes.write().unwrap().store(
|
||||||
pubkey,
|
pubkey,
|
||||||
account,
|
account,
|
||||||
self.stake_program_v2_enabled(),
|
|
||||||
self.check_init_vote_data_enabled(),
|
self.check_init_vote_data_enabled(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -5221,7 +5164,6 @@ impl Bank {
|
|||||||
if let Some(old_vote_account) = self.stakes.write().unwrap().store(
|
if let Some(old_vote_account) = self.stakes.write().unwrap().store(
|
||||||
pubkey,
|
pubkey,
|
||||||
account,
|
account,
|
||||||
self.stake_program_v2_enabled(),
|
|
||||||
self.check_init_vote_data_enabled(),
|
self.check_init_vote_data_enabled(),
|
||||||
) {
|
) {
|
||||||
// TODO: one of the indices is redundant.
|
// TODO: one of the indices is redundant.
|
||||||
@ -5447,11 +5389,6 @@ impl Bank {
|
|||||||
.is_active(&feature_set::no_overflow_rent_distribution::id())
|
.is_active(&feature_set::no_overflow_rent_distribution::id())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn stake_program_v2_enabled(&self) -> bool {
|
|
||||||
self.feature_set
|
|
||||||
.is_active(&feature_set::stake_program_v2::id())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn check_init_vote_data_enabled(&self) -> bool {
|
pub fn check_init_vote_data_enabled(&self) -> bool {
|
||||||
self.feature_set
|
self.feature_set
|
||||||
.is_active(&feature_set::check_init_vote_data::id())
|
.is_active(&feature_set::check_init_vote_data::id())
|
||||||
@ -5531,16 +5468,6 @@ impl Bank {
|
|||||||
if new_feature_activations.contains(&feature_set::spl_token_v2_set_authority_fix::id()) {
|
if new_feature_activations.contains(&feature_set::spl_token_v2_set_authority_fix::id()) {
|
||||||
self.apply_spl_token_v2_set_authority_fix();
|
self.apply_spl_token_v2_set_authority_fix();
|
||||||
}
|
}
|
||||||
// Remove me after a while around v1.6
|
|
||||||
if !self.no_stake_rewrite.load(Relaxed)
|
|
||||||
&& new_feature_activations.contains(&feature_set::rewrite_stake::id())
|
|
||||||
{
|
|
||||||
// to avoid any potential risk of wrongly rewriting accounts in the future,
|
|
||||||
// only do this once, taking small risk of unknown
|
|
||||||
// bugs which again creates bad stake accounts..
|
|
||||||
|
|
||||||
self.rewrite_stakes();
|
|
||||||
}
|
|
||||||
if new_feature_activations.contains(&feature_set::rent_for_sysvars::id()) {
|
if new_feature_activations.contains(&feature_set::rent_for_sysvars::id()) {
|
||||||
// when this feature is activated, immediately all of existing sysvars are susceptible
|
// when this feature is activated, immediately all of existing sysvars are susceptible
|
||||||
// to rent collection and account data removal due to insufficient balance due to only
|
// to rent collection and account data removal due to insufficient balance due to only
|
||||||
@ -7836,7 +7763,7 @@ pub(crate) mod tests {
|
|||||||
.map(move |(_stake_pubkey, stake_account)| (stake_account, vote_account))
|
.map(move |(_stake_pubkey, stake_account)| (stake_account, vote_account))
|
||||||
})
|
})
|
||||||
.map(|(stake_account, vote_account)| {
|
.map(|(stake_account, vote_account)| {
|
||||||
stake_state::calculate_points(stake_account, vote_account, None, true).unwrap_or(0)
|
stake_state::calculate_points(stake_account, vote_account, None).unwrap_or(0)
|
||||||
})
|
})
|
||||||
.sum();
|
.sum();
|
||||||
|
|
||||||
@ -9382,7 +9309,7 @@ pub(crate) mod tests {
|
|||||||
// epoch_stakes are a snapshot at the leader_schedule_slot_offset boundary
|
// epoch_stakes are a snapshot at the leader_schedule_slot_offset boundary
|
||||||
// in the prior epoch (0 in this case)
|
// in the prior epoch (0 in this case)
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
leader_stake.stake(0, None, true),
|
leader_stake.stake(0, None),
|
||||||
vote_accounts.unwrap().get(&leader_vote_account).unwrap().0
|
vote_accounts.unwrap().get(&leader_vote_account).unwrap().0
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -9398,7 +9325,7 @@ pub(crate) mod tests {
|
|||||||
|
|
||||||
assert!(child.epoch_vote_accounts(epoch).is_some());
|
assert!(child.epoch_vote_accounts(epoch).is_some());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
leader_stake.stake(child.epoch(), None, true),
|
leader_stake.stake(child.epoch(), None),
|
||||||
child
|
child
|
||||||
.epoch_vote_accounts(epoch)
|
.epoch_vote_accounts(epoch)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
@ -9416,7 +9343,7 @@ pub(crate) mod tests {
|
|||||||
);
|
);
|
||||||
assert!(child.epoch_vote_accounts(epoch).is_some());
|
assert!(child.epoch_vote_accounts(epoch).is_some());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
leader_stake.stake(child.epoch(), None, true),
|
leader_stake.stake(child.epoch(), None),
|
||||||
child
|
child
|
||||||
.epoch_vote_accounts(epoch)
|
.epoch_vote_accounts(epoch)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
@ -13365,26 +13292,6 @@ pub(crate) mod tests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_stake_rewrite() {
|
|
||||||
let GenesisConfigInfo { genesis_config, .. } =
|
|
||||||
create_genesis_config_with_leader(500, &solana_sdk::pubkey::new_rand(), 1);
|
|
||||||
let bank = Arc::new(Bank::new_for_tests(&genesis_config));
|
|
||||||
|
|
||||||
// quickest way of creting bad stake account
|
|
||||||
let bootstrap_stake_pubkey = bank
|
|
||||||
.cloned_stake_delegations()
|
|
||||||
.keys()
|
|
||||||
.next()
|
|
||||||
.copied()
|
|
||||||
.unwrap();
|
|
||||||
let mut bootstrap_stake_account = bank.get_account(&bootstrap_stake_pubkey).unwrap();
|
|
||||||
bootstrap_stake_account.set_lamports(10000000);
|
|
||||||
bank.store_account(&bootstrap_stake_pubkey, &bootstrap_stake_account);
|
|
||||||
|
|
||||||
assert_eq!(bank.rewrite_stakes(), (1, 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_get_inflation_start_slot_devnet_testnet() {
|
fn test_get_inflation_start_slot_devnet_testnet() {
|
||||||
let GenesisConfigInfo {
|
let GenesisConfigInfo {
|
||||||
|
@ -39,7 +39,7 @@ impl Stakes {
|
|||||||
pub fn history(&self) -> &StakeHistory {
|
pub fn history(&self) -> &StakeHistory {
|
||||||
&self.stake_history
|
&self.stake_history
|
||||||
}
|
}
|
||||||
pub fn clone_with_epoch(&self, next_epoch: Epoch, fix_stake_deactivate: bool) -> Self {
|
pub fn clone_with_epoch(&self, next_epoch: Epoch) -> Self {
|
||||||
let prev_epoch = self.epoch;
|
let prev_epoch = self.epoch;
|
||||||
if prev_epoch == next_epoch {
|
if prev_epoch == next_epoch {
|
||||||
self.clone()
|
self.clone()
|
||||||
@ -54,7 +54,6 @@ impl Stakes {
|
|||||||
.iter()
|
.iter()
|
||||||
.map(|(_pubkey, stake_delegation)| stake_delegation),
|
.map(|(_pubkey, stake_delegation)| stake_delegation),
|
||||||
Some(&self.stake_history),
|
Some(&self.stake_history),
|
||||||
fix_stake_deactivate,
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -67,7 +66,6 @@ impl Stakes {
|
|||||||
pubkey,
|
pubkey,
|
||||||
next_epoch,
|
next_epoch,
|
||||||
Some(&stake_history_upto_prev_epoch),
|
Some(&stake_history_upto_prev_epoch),
|
||||||
fix_stake_deactivate,
|
|
||||||
);
|
);
|
||||||
(*pubkey, (stake, account.clone()))
|
(*pubkey, (stake, account.clone()))
|
||||||
})
|
})
|
||||||
@ -89,13 +87,12 @@ impl Stakes {
|
|||||||
voter_pubkey: &Pubkey,
|
voter_pubkey: &Pubkey,
|
||||||
epoch: Epoch,
|
epoch: Epoch,
|
||||||
stake_history: Option<&StakeHistory>,
|
stake_history: Option<&StakeHistory>,
|
||||||
fix_stake_deactivate: bool,
|
|
||||||
) -> u64 {
|
) -> u64 {
|
||||||
self.stake_delegations
|
self.stake_delegations
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(_, stake_delegation)| {
|
.map(|(_, stake_delegation)| {
|
||||||
if &stake_delegation.voter_pubkey == voter_pubkey {
|
if &stake_delegation.voter_pubkey == voter_pubkey {
|
||||||
stake_delegation.stake(epoch, stake_history, fix_stake_deactivate)
|
stake_delegation.stake(epoch, stake_history)
|
||||||
} else {
|
} else {
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
@ -125,7 +122,6 @@ impl Stakes {
|
|||||||
&mut self,
|
&mut self,
|
||||||
pubkey: &Pubkey,
|
pubkey: &Pubkey,
|
||||||
account: &AccountSharedData,
|
account: &AccountSharedData,
|
||||||
fix_stake_deactivate: bool,
|
|
||||||
check_vote_init: bool,
|
check_vote_init: bool,
|
||||||
) -> Option<VoteAccount> {
|
) -> Option<VoteAccount> {
|
||||||
if solana_vote_program::check_id(account.owner()) {
|
if solana_vote_program::check_id(account.owner()) {
|
||||||
@ -139,14 +135,7 @@ impl Stakes {
|
|||||||
&& !(check_vote_init && VoteState::is_uninitialized_no_deser(account.data()))
|
&& !(check_vote_init && VoteState::is_uninitialized_no_deser(account.data()))
|
||||||
{
|
{
|
||||||
let stake = old.as_ref().map_or_else(
|
let stake = old.as_ref().map_or_else(
|
||||||
|| {
|
|| self.calculate_stake(pubkey, self.epoch, Some(&self.stake_history)),
|
||||||
self.calculate_stake(
|
|
||||||
pubkey,
|
|
||||||
self.epoch,
|
|
||||||
Some(&self.stake_history),
|
|
||||||
fix_stake_deactivate,
|
|
||||||
)
|
|
||||||
},
|
|
||||||
|v| v.0,
|
|v| v.0,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -159,7 +148,7 @@ impl Stakes {
|
|||||||
let old_stake = self.stake_delegations.get(pubkey).map(|delegation| {
|
let old_stake = self.stake_delegations.get(pubkey).map(|delegation| {
|
||||||
(
|
(
|
||||||
delegation.voter_pubkey,
|
delegation.voter_pubkey,
|
||||||
delegation.stake(self.epoch, Some(&self.stake_history), fix_stake_deactivate),
|
delegation.stake(self.epoch, Some(&self.stake_history)),
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -169,11 +158,7 @@ impl Stakes {
|
|||||||
(
|
(
|
||||||
delegation.voter_pubkey,
|
delegation.voter_pubkey,
|
||||||
if account.lamports() != 0 {
|
if account.lamports() != 0 {
|
||||||
delegation.stake(
|
delegation.stake(self.epoch, Some(&self.stake_history))
|
||||||
self.epoch,
|
|
||||||
Some(&self.stake_history),
|
|
||||||
fix_stake_deactivate,
|
|
||||||
)
|
|
||||||
} else {
|
} else {
|
||||||
// when account is removed (lamports == 0), this special `else` clause ensures
|
// when account is removed (lamports == 0), this special `else` clause ensures
|
||||||
// resetting cached stake value below, even if the account happens to be
|
// resetting cached stake value below, even if the account happens to be
|
||||||
@ -312,44 +297,44 @@ pub mod tests {
|
|||||||
let ((vote_pubkey, vote_account), (stake_pubkey, mut stake_account)) =
|
let ((vote_pubkey, vote_account), (stake_pubkey, mut stake_account)) =
|
||||||
create_staked_node_accounts(10);
|
create_staked_node_accounts(10);
|
||||||
|
|
||||||
stakes.store(&vote_pubkey, &vote_account, true, true);
|
stakes.store(&vote_pubkey, &vote_account, true);
|
||||||
stakes.store(&stake_pubkey, &stake_account, true, true);
|
stakes.store(&stake_pubkey, &stake_account, true);
|
||||||
let stake = stake_state::stake_from(&stake_account).unwrap();
|
let stake = stake_state::stake_from(&stake_account).unwrap();
|
||||||
{
|
{
|
||||||
let vote_accounts = stakes.vote_accounts();
|
let vote_accounts = stakes.vote_accounts();
|
||||||
assert!(vote_accounts.get(&vote_pubkey).is_some());
|
assert!(vote_accounts.get(&vote_pubkey).is_some());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
vote_accounts.get(&vote_pubkey).unwrap().0,
|
vote_accounts.get(&vote_pubkey).unwrap().0,
|
||||||
stake.stake(i, None, true)
|
stake.stake(i, None)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
stake_account.set_lamports(42);
|
stake_account.set_lamports(42);
|
||||||
stakes.store(&stake_pubkey, &stake_account, true, true);
|
stakes.store(&stake_pubkey, &stake_account, true);
|
||||||
{
|
{
|
||||||
let vote_accounts = stakes.vote_accounts();
|
let vote_accounts = stakes.vote_accounts();
|
||||||
assert!(vote_accounts.get(&vote_pubkey).is_some());
|
assert!(vote_accounts.get(&vote_pubkey).is_some());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
vote_accounts.get(&vote_pubkey).unwrap().0,
|
vote_accounts.get(&vote_pubkey).unwrap().0,
|
||||||
stake.stake(i, None, true)
|
stake.stake(i, None)
|
||||||
); // stays old stake, because only 10 is activated
|
); // stays old stake, because only 10 is activated
|
||||||
}
|
}
|
||||||
|
|
||||||
// activate more
|
// activate more
|
||||||
let (_stake_pubkey, mut stake_account) = create_stake_account(42, &vote_pubkey);
|
let (_stake_pubkey, mut stake_account) = create_stake_account(42, &vote_pubkey);
|
||||||
stakes.store(&stake_pubkey, &stake_account, true, true);
|
stakes.store(&stake_pubkey, &stake_account, true);
|
||||||
let stake = stake_state::stake_from(&stake_account).unwrap();
|
let stake = stake_state::stake_from(&stake_account).unwrap();
|
||||||
{
|
{
|
||||||
let vote_accounts = stakes.vote_accounts();
|
let vote_accounts = stakes.vote_accounts();
|
||||||
assert!(vote_accounts.get(&vote_pubkey).is_some());
|
assert!(vote_accounts.get(&vote_pubkey).is_some());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
vote_accounts.get(&vote_pubkey).unwrap().0,
|
vote_accounts.get(&vote_pubkey).unwrap().0,
|
||||||
stake.stake(i, None, true)
|
stake.stake(i, None)
|
||||||
); // now stake of 42 is activated
|
); // now stake of 42 is activated
|
||||||
}
|
}
|
||||||
|
|
||||||
stake_account.set_lamports(0);
|
stake_account.set_lamports(0);
|
||||||
stakes.store(&stake_pubkey, &stake_account, true, true);
|
stakes.store(&stake_pubkey, &stake_account, true);
|
||||||
{
|
{
|
||||||
let vote_accounts = stakes.vote_accounts();
|
let vote_accounts = stakes.vote_accounts();
|
||||||
assert!(vote_accounts.get(&vote_pubkey).is_some());
|
assert!(vote_accounts.get(&vote_pubkey).is_some());
|
||||||
@ -367,14 +352,14 @@ pub mod tests {
|
|||||||
let ((vote_pubkey, vote_account), (stake_pubkey, stake_account)) =
|
let ((vote_pubkey, vote_account), (stake_pubkey, stake_account)) =
|
||||||
create_staked_node_accounts(10);
|
create_staked_node_accounts(10);
|
||||||
|
|
||||||
stakes.store(&vote_pubkey, &vote_account, true, true);
|
stakes.store(&vote_pubkey, &vote_account, true);
|
||||||
stakes.store(&stake_pubkey, &stake_account, true, true);
|
stakes.store(&stake_pubkey, &stake_account, true);
|
||||||
|
|
||||||
let ((vote11_pubkey, vote11_account), (stake11_pubkey, stake11_account)) =
|
let ((vote11_pubkey, vote11_account), (stake11_pubkey, stake11_account)) =
|
||||||
create_staked_node_accounts(20);
|
create_staked_node_accounts(20);
|
||||||
|
|
||||||
stakes.store(&vote11_pubkey, &vote11_account, true, true);
|
stakes.store(&vote11_pubkey, &vote11_account, true);
|
||||||
stakes.store(&stake11_pubkey, &stake11_account, true, true);
|
stakes.store(&stake11_pubkey, &stake11_account, true);
|
||||||
|
|
||||||
let vote11_node_pubkey = VoteState::from(&vote11_account).unwrap().node_pubkey;
|
let vote11_node_pubkey = VoteState::from(&vote11_account).unwrap().node_pubkey;
|
||||||
|
|
||||||
@ -391,8 +376,8 @@ pub mod tests {
|
|||||||
let ((vote_pubkey, mut vote_account), (stake_pubkey, stake_account)) =
|
let ((vote_pubkey, mut vote_account), (stake_pubkey, stake_account)) =
|
||||||
create_staked_node_accounts(10);
|
create_staked_node_accounts(10);
|
||||||
|
|
||||||
stakes.store(&vote_pubkey, &vote_account, true, true);
|
stakes.store(&vote_pubkey, &vote_account, true);
|
||||||
stakes.store(&stake_pubkey, &stake_account, true, true);
|
stakes.store(&stake_pubkey, &stake_account, true);
|
||||||
|
|
||||||
{
|
{
|
||||||
let vote_accounts = stakes.vote_accounts();
|
let vote_accounts = stakes.vote_accounts();
|
||||||
@ -401,7 +386,7 @@ pub mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
vote_account.set_lamports(0);
|
vote_account.set_lamports(0);
|
||||||
stakes.store(&vote_pubkey, &vote_account, true, true);
|
stakes.store(&vote_pubkey, &vote_account, true);
|
||||||
|
|
||||||
{
|
{
|
||||||
let vote_accounts = stakes.vote_accounts();
|
let vote_accounts = stakes.vote_accounts();
|
||||||
@ -409,7 +394,7 @@ pub mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
vote_account.set_lamports(1);
|
vote_account.set_lamports(1);
|
||||||
stakes.store(&vote_pubkey, &vote_account, true, true);
|
stakes.store(&vote_pubkey, &vote_account, true);
|
||||||
|
|
||||||
{
|
{
|
||||||
let vote_accounts = stakes.vote_accounts();
|
let vote_accounts = stakes.vote_accounts();
|
||||||
@ -422,7 +407,7 @@ pub mod tests {
|
|||||||
let mut pushed = vote_account.data().to_vec();
|
let mut pushed = vote_account.data().to_vec();
|
||||||
pushed.push(0);
|
pushed.push(0);
|
||||||
vote_account.set_data(pushed);
|
vote_account.set_data(pushed);
|
||||||
stakes.store(&vote_pubkey, &vote_account, true, true);
|
stakes.store(&vote_pubkey, &vote_account, true);
|
||||||
|
|
||||||
{
|
{
|
||||||
let vote_accounts = stakes.vote_accounts();
|
let vote_accounts = stakes.vote_accounts();
|
||||||
@ -433,7 +418,7 @@ pub mod tests {
|
|||||||
let default_vote_state = VoteState::default();
|
let default_vote_state = VoteState::default();
|
||||||
let versioned = VoteStateVersions::new_current(default_vote_state);
|
let versioned = VoteStateVersions::new_current(default_vote_state);
|
||||||
VoteState::to(&versioned, &mut vote_account).unwrap();
|
VoteState::to(&versioned, &mut vote_account).unwrap();
|
||||||
stakes.store(&vote_pubkey, &vote_account, true, true);
|
stakes.store(&vote_pubkey, &vote_account, true);
|
||||||
|
|
||||||
{
|
{
|
||||||
let vote_accounts = stakes.vote_accounts();
|
let vote_accounts = stakes.vote_accounts();
|
||||||
@ -441,7 +426,7 @@ pub mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
vote_account.set_data(cache_data);
|
vote_account.set_data(cache_data);
|
||||||
stakes.store(&vote_pubkey, &vote_account, true, true);
|
stakes.store(&vote_pubkey, &vote_account, true);
|
||||||
|
|
||||||
{
|
{
|
||||||
let vote_accounts = stakes.vote_accounts();
|
let vote_accounts = stakes.vote_accounts();
|
||||||
@ -463,11 +448,11 @@ pub mod tests {
|
|||||||
let ((vote_pubkey2, vote_account2), (_stake_pubkey2, stake_account2)) =
|
let ((vote_pubkey2, vote_account2), (_stake_pubkey2, stake_account2)) =
|
||||||
create_staked_node_accounts(10);
|
create_staked_node_accounts(10);
|
||||||
|
|
||||||
stakes.store(&vote_pubkey, &vote_account, true, true);
|
stakes.store(&vote_pubkey, &vote_account, true);
|
||||||
stakes.store(&vote_pubkey2, &vote_account2, true, true);
|
stakes.store(&vote_pubkey2, &vote_account2, true);
|
||||||
|
|
||||||
// delegates to vote_pubkey
|
// delegates to vote_pubkey
|
||||||
stakes.store(&stake_pubkey, &stake_account, true, true);
|
stakes.store(&stake_pubkey, &stake_account, true);
|
||||||
|
|
||||||
let stake = stake_state::stake_from(&stake_account).unwrap();
|
let stake = stake_state::stake_from(&stake_account).unwrap();
|
||||||
|
|
||||||
@ -476,14 +461,14 @@ pub mod tests {
|
|||||||
assert!(vote_accounts.get(&vote_pubkey).is_some());
|
assert!(vote_accounts.get(&vote_pubkey).is_some());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
vote_accounts.get(&vote_pubkey).unwrap().0,
|
vote_accounts.get(&vote_pubkey).unwrap().0,
|
||||||
stake.stake(stakes.epoch, Some(&stakes.stake_history), true)
|
stake.stake(stakes.epoch, Some(&stakes.stake_history))
|
||||||
);
|
);
|
||||||
assert!(vote_accounts.get(&vote_pubkey2).is_some());
|
assert!(vote_accounts.get(&vote_pubkey2).is_some());
|
||||||
assert_eq!(vote_accounts.get(&vote_pubkey2).unwrap().0, 0);
|
assert_eq!(vote_accounts.get(&vote_pubkey2).unwrap().0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// delegates to vote_pubkey2
|
// delegates to vote_pubkey2
|
||||||
stakes.store(&stake_pubkey, &stake_account2, true, true);
|
stakes.store(&stake_pubkey, &stake_account2, true);
|
||||||
|
|
||||||
{
|
{
|
||||||
let vote_accounts = stakes.vote_accounts();
|
let vote_accounts = stakes.vote_accounts();
|
||||||
@ -492,7 +477,7 @@ pub mod tests {
|
|||||||
assert!(vote_accounts.get(&vote_pubkey2).is_some());
|
assert!(vote_accounts.get(&vote_pubkey2).is_some());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
vote_accounts.get(&vote_pubkey2).unwrap().0,
|
vote_accounts.get(&vote_pubkey2).unwrap().0,
|
||||||
stake.stake(stakes.epoch, Some(&stakes.stake_history), true)
|
stake.stake(stakes.epoch, Some(&stakes.stake_history))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -508,11 +493,11 @@ pub mod tests {
|
|||||||
|
|
||||||
let (stake_pubkey2, stake_account2) = create_stake_account(10, &vote_pubkey);
|
let (stake_pubkey2, stake_account2) = create_stake_account(10, &vote_pubkey);
|
||||||
|
|
||||||
stakes.store(&vote_pubkey, &vote_account, true, true);
|
stakes.store(&vote_pubkey, &vote_account, true);
|
||||||
|
|
||||||
// delegates to vote_pubkey
|
// delegates to vote_pubkey
|
||||||
stakes.store(&stake_pubkey, &stake_account, true, true);
|
stakes.store(&stake_pubkey, &stake_account, true);
|
||||||
stakes.store(&stake_pubkey2, &stake_account2, true, true);
|
stakes.store(&stake_pubkey2, &stake_account2, true);
|
||||||
|
|
||||||
{
|
{
|
||||||
let vote_accounts = stakes.vote_accounts();
|
let vote_accounts = stakes.vote_accounts();
|
||||||
@ -527,23 +512,23 @@ pub mod tests {
|
|||||||
let ((vote_pubkey, vote_account), (stake_pubkey, stake_account)) =
|
let ((vote_pubkey, vote_account), (stake_pubkey, stake_account)) =
|
||||||
create_staked_node_accounts(10);
|
create_staked_node_accounts(10);
|
||||||
|
|
||||||
stakes.store(&vote_pubkey, &vote_account, true, true);
|
stakes.store(&vote_pubkey, &vote_account, true);
|
||||||
stakes.store(&stake_pubkey, &stake_account, true, true);
|
stakes.store(&stake_pubkey, &stake_account, true);
|
||||||
let stake = stake_state::stake_from(&stake_account).unwrap();
|
let stake = stake_state::stake_from(&stake_account).unwrap();
|
||||||
|
|
||||||
{
|
{
|
||||||
let vote_accounts = stakes.vote_accounts();
|
let vote_accounts = stakes.vote_accounts();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
vote_accounts.get(&vote_pubkey).unwrap().0,
|
vote_accounts.get(&vote_pubkey).unwrap().0,
|
||||||
stake.stake(stakes.epoch, Some(&stakes.stake_history), true)
|
stake.stake(stakes.epoch, Some(&stakes.stake_history))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
let stakes = stakes.clone_with_epoch(3, true);
|
let stakes = stakes.clone_with_epoch(3);
|
||||||
{
|
{
|
||||||
let vote_accounts = stakes.vote_accounts();
|
let vote_accounts = stakes.vote_accounts();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
vote_accounts.get(&vote_pubkey).unwrap().0,
|
vote_accounts.get(&vote_pubkey).unwrap().0,
|
||||||
stake.stake(stakes.epoch, Some(&stakes.stake_history), true)
|
stake.stake(stakes.epoch, Some(&stakes.stake_history))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -558,8 +543,8 @@ pub mod tests {
|
|||||||
let ((vote_pubkey, vote_account), (stake_pubkey, stake_account)) =
|
let ((vote_pubkey, vote_account), (stake_pubkey, stake_account)) =
|
||||||
create_staked_node_accounts(10);
|
create_staked_node_accounts(10);
|
||||||
|
|
||||||
stakes.store(&vote_pubkey, &vote_account, true, true);
|
stakes.store(&vote_pubkey, &vote_account, true);
|
||||||
stakes.store(&stake_pubkey, &stake_account, true, true);
|
stakes.store(&stake_pubkey, &stake_account, true);
|
||||||
|
|
||||||
{
|
{
|
||||||
let vote_accounts = stakes.vote_accounts();
|
let vote_accounts = stakes.vote_accounts();
|
||||||
@ -572,7 +557,6 @@ pub mod tests {
|
|||||||
&stake_pubkey,
|
&stake_pubkey,
|
||||||
&AccountSharedData::new(1, 0, &stake::program::id()),
|
&AccountSharedData::new(1, 0, &stake::program::id()),
|
||||||
true,
|
true,
|
||||||
true,
|
|
||||||
);
|
);
|
||||||
{
|
{
|
||||||
let vote_accounts = stakes.vote_accounts();
|
let vote_accounts = stakes.vote_accounts();
|
||||||
@ -602,14 +586,14 @@ pub mod tests {
|
|||||||
let genesis_epoch = 0;
|
let genesis_epoch = 0;
|
||||||
let ((vote_pubkey, vote_account), (stake_pubkey, stake_account)) =
|
let ((vote_pubkey, vote_account), (stake_pubkey, stake_account)) =
|
||||||
create_warming_staked_node_accounts(10, genesis_epoch);
|
create_warming_staked_node_accounts(10, genesis_epoch);
|
||||||
stakes.store(&vote_pubkey, &vote_account, true, true);
|
stakes.store(&vote_pubkey, &vote_account, true);
|
||||||
stakes.store(&stake_pubkey, &stake_account, true, true);
|
stakes.store(&stake_pubkey, &stake_account, true);
|
||||||
|
|
||||||
assert_eq!(stakes.vote_balance_and_staked(), 11);
|
assert_eq!(stakes.vote_balance_and_staked(), 11);
|
||||||
assert_eq!(stakes.vote_balance_and_warmed_staked(), 1);
|
assert_eq!(stakes.vote_balance_and_warmed_staked(), 1);
|
||||||
|
|
||||||
for (epoch, expected_warmed_stake) in ((genesis_epoch + 1)..=3).zip(&[2, 3, 4]) {
|
for (epoch, expected_warmed_stake) in ((genesis_epoch + 1)..=3).zip(&[2, 3, 4]) {
|
||||||
stakes = stakes.clone_with_epoch(epoch, true);
|
stakes = stakes.clone_with_epoch(epoch);
|
||||||
// vote_balance_and_staked() always remain to return same lamports
|
// vote_balance_and_staked() always remain to return same lamports
|
||||||
// while vote_balance_and_warmed_staked() gradually increases
|
// while vote_balance_and_warmed_staked() gradually increases
|
||||||
assert_eq!(stakes.vote_balance_and_staked(), 11);
|
assert_eq!(stakes.vote_balance_and_staked(), 11);
|
||||||
|
@ -81,7 +81,6 @@ fn warmed_up(bank: &Bank, stake_pubkey: &Pubkey) -> bool {
|
|||||||
)
|
)
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
),
|
),
|
||||||
true,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -96,7 +95,6 @@ fn get_staked(bank: &Bank, stake_pubkey: &Pubkey) -> u64 {
|
|||||||
)
|
)
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
),
|
),
|
||||||
true,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -282,14 +282,8 @@ impl Delegation {
|
|||||||
self.activation_epoch == std::u64::MAX
|
self.activation_epoch == std::u64::MAX
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn stake(
|
pub fn stake(&self, epoch: Epoch, history: Option<&StakeHistory>) -> u64 {
|
||||||
&self,
|
self.stake_activating_and_deactivating(epoch, history).0
|
||||||
epoch: Epoch,
|
|
||||||
history: Option<&StakeHistory>,
|
|
||||||
fix_stake_deactivate: bool,
|
|
||||||
) -> u64 {
|
|
||||||
self.stake_activating_and_deactivating(epoch, history, fix_stake_deactivate)
|
|
||||||
.0
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// returned tuple is (effective, activating, deactivating) stake
|
// returned tuple is (effective, activating, deactivating) stake
|
||||||
@ -298,13 +292,11 @@ impl Delegation {
|
|||||||
&self,
|
&self,
|
||||||
target_epoch: Epoch,
|
target_epoch: Epoch,
|
||||||
history: Option<&StakeHistory>,
|
history: Option<&StakeHistory>,
|
||||||
fix_stake_deactivate: bool,
|
|
||||||
) -> (u64, u64, u64) {
|
) -> (u64, u64, u64) {
|
||||||
let delegated_stake = self.stake;
|
let delegated_stake = self.stake;
|
||||||
|
|
||||||
// first, calculate an effective and activating stake
|
// first, calculate an effective and activating stake
|
||||||
let (effective_stake, activating_stake) =
|
let (effective_stake, activating_stake) = self.stake_and_activating(target_epoch, history);
|
||||||
self.stake_and_activating(target_epoch, history, fix_stake_deactivate);
|
|
||||||
|
|
||||||
// then de-activate some portion if necessary
|
// then de-activate some portion if necessary
|
||||||
if target_epoch < self.deactivation_epoch {
|
if target_epoch < self.deactivation_epoch {
|
||||||
@ -381,14 +373,13 @@ impl Delegation {
|
|||||||
&self,
|
&self,
|
||||||
target_epoch: Epoch,
|
target_epoch: Epoch,
|
||||||
history: Option<&StakeHistory>,
|
history: Option<&StakeHistory>,
|
||||||
fix_stake_deactivate: bool,
|
|
||||||
) -> (u64, u64) {
|
) -> (u64, u64) {
|
||||||
let delegated_stake = self.stake;
|
let delegated_stake = self.stake;
|
||||||
|
|
||||||
if self.is_bootstrap() {
|
if self.is_bootstrap() {
|
||||||
// fully effective immediately
|
// fully effective immediately
|
||||||
(delegated_stake, 0)
|
(delegated_stake, 0)
|
||||||
} else if fix_stake_deactivate && self.activation_epoch == self.deactivation_epoch {
|
} else if self.activation_epoch == self.deactivation_epoch {
|
||||||
// activated but instantly deactivated; no stake at all regardless of target_epoch
|
// activated but instantly deactivated; no stake at all regardless of target_epoch
|
||||||
// this must be after the bootstrap check and before all-is-activating check
|
// this must be after the bootstrap check and before all-is-activating check
|
||||||
(0, 0)
|
(0, 0)
|
||||||
@ -463,27 +454,6 @@ impl Delegation {
|
|||||||
(delegated_stake, 0)
|
(delegated_stake, 0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn rewrite_stake(
|
|
||||||
&mut self,
|
|
||||||
account_balance: u64,
|
|
||||||
rent_exempt_balance: u64,
|
|
||||||
) -> Option<(u64, u64)> {
|
|
||||||
// note that this will intentionally overwrite innocent
|
|
||||||
// deactivated-then-immeditealy-withdrawn stake accounts as well
|
|
||||||
// this is chosen to minimize the risks from complicated logic,
|
|
||||||
// over some unneeded rewrites
|
|
||||||
let corrected_stake = account_balance.saturating_sub(rent_exempt_balance);
|
|
||||||
if self.stake != corrected_stake {
|
|
||||||
// this could result in creating a 0-staked account;
|
|
||||||
// rewards and staking calc can handle it.
|
|
||||||
let (old, new) = (self.stake, corrected_stake);
|
|
||||||
self.stake = corrected_stake;
|
|
||||||
Some((old, new))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default, Serialize, Deserialize, PartialEq, Clone, Copy, AbiExample)]
|
#[derive(Debug, Default, Serialize, Deserialize, PartialEq, Clone, Copy, AbiExample)]
|
||||||
@ -494,13 +464,8 @@ pub struct Stake {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Stake {
|
impl Stake {
|
||||||
pub fn stake(
|
pub fn stake(&self, epoch: Epoch, history: Option<&StakeHistory>) -> u64 {
|
||||||
&self,
|
self.delegation.stake(epoch, history)
|
||||||
epoch: Epoch,
|
|
||||||
history: Option<&StakeHistory>,
|
|
||||||
fix_stake_deactivate: bool,
|
|
||||||
) -> u64 {
|
|
||||||
self.delegation.stake(epoch, history, fix_stake_deactivate)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn split(
|
pub fn split(
|
||||||
|
@ -63,14 +63,6 @@ pub mod no_overflow_rent_distribution {
|
|||||||
solana_sdk::declare_id!("4kpdyrcj5jS47CZb2oJGfVxjYbsMm2Kx97gFyZrxxwXz");
|
solana_sdk::declare_id!("4kpdyrcj5jS47CZb2oJGfVxjYbsMm2Kx97gFyZrxxwXz");
|
||||||
}
|
}
|
||||||
|
|
||||||
pub mod stake_program_v2 {
|
|
||||||
solana_sdk::declare_id!("Gvd9gGJZDHGMNf1b3jkxrfBQSR5etrfTQSBNKCvLSFJN");
|
|
||||||
}
|
|
||||||
|
|
||||||
pub mod rewrite_stake {
|
|
||||||
solana_sdk::declare_id!("6ap2eGy7wx5JmsWUmQ5sHwEWrFSDUxSti2k5Hbfv5BZG");
|
|
||||||
}
|
|
||||||
|
|
||||||
pub mod filter_stake_delegation_accounts {
|
pub mod filter_stake_delegation_accounts {
|
||||||
solana_sdk::declare_id!("GE7fRxmW46K6EmCD9AMZSbnaJ2e3LfqCZzdHi9hmYAgi");
|
solana_sdk::declare_id!("GE7fRxmW46K6EmCD9AMZSbnaJ2e3LfqCZzdHi9hmYAgi");
|
||||||
}
|
}
|
||||||
@ -212,8 +204,6 @@ lazy_static! {
|
|||||||
(full_inflation::devnet_and_testnet::id(), "full inflation on devnet and testnet"),
|
(full_inflation::devnet_and_testnet::id(), "full inflation on devnet and testnet"),
|
||||||
(spl_token_v2_multisig_fix::id(), "spl-token multisig fix"),
|
(spl_token_v2_multisig_fix::id(), "spl-token multisig fix"),
|
||||||
(no_overflow_rent_distribution::id(), "no overflow rent distribution"),
|
(no_overflow_rent_distribution::id(), "no overflow rent distribution"),
|
||||||
(stake_program_v2::id(), "solana_stake_program v2"),
|
|
||||||
(rewrite_stake::id(), "rewrite stake"),
|
|
||||||
(filter_stake_delegation_accounts::id(), "filter stake_delegation_accounts #14062"),
|
(filter_stake_delegation_accounts::id(), "filter stake_delegation_accounts #14062"),
|
||||||
(stake_program_v3::id(), "solana_stake_program v3"),
|
(stake_program_v3::id(), "solana_stake_program v3"),
|
||||||
(require_custodian_for_locked_stake_authorize::id(), "require custodian to authorize withdrawer change for locked stake"),
|
(require_custodian_for_locked_stake_authorize::id(), "require custodian to authorize withdrawer change for locked stake"),
|
||||||
|
Reference in New Issue
Block a user