adds StakeAccount type embodying an Account and a StakeState
The added type does sanity checks on the Account and stores deserialized StakeState. Following commits will use this type instead of Delegation in Stakes.
This commit is contained in:
parent
02bfb85c16
commit
8c4d6357fe
|
@ -56,6 +56,7 @@ use {
|
|||
inline_spl_associated_token_account, inline_spl_token,
|
||||
message_processor::MessageProcessor,
|
||||
rent_collector::{CollectedInfo, RentCollector},
|
||||
stake_account::{self, StakeAccount},
|
||||
stake_weighted_timestamp::{
|
||||
calculate_stake_weighted_timestamp, MaxAllowableDrift, MAX_ALLOWABLE_DRIFT_PERCENTAGE,
|
||||
MAX_ALLOWABLE_DRIFT_PERCENTAGE_FAST, MAX_ALLOWABLE_DRIFT_PERCENTAGE_SLOW,
|
||||
|
@ -1262,7 +1263,7 @@ pub struct Bank {
|
|||
struct VoteWithStakeDelegations {
|
||||
vote_state: Arc<VoteState>,
|
||||
vote_account: AccountSharedData,
|
||||
delegations: Vec<(Pubkey, (StakeState, AccountSharedData))>,
|
||||
delegations: Vec<(Pubkey, StakeAccount)>,
|
||||
}
|
||||
|
||||
struct LoadVoteAndStakeAccountsResult {
|
||||
|
@ -2616,31 +2617,28 @@ impl Bank {
|
|||
if invalid_vote_keys.contains_key(vote_pubkey) {
|
||||
return;
|
||||
}
|
||||
|
||||
let stake_delegation = match self.get_account_with_fixed_root(stake_pubkey) {
|
||||
Some(stake_account) => {
|
||||
if stake_account.owner() != &solana_stake_program::id() {
|
||||
invalid_stake_keys
|
||||
.insert(*stake_pubkey, InvalidCacheEntryReason::WrongOwner);
|
||||
return;
|
||||
}
|
||||
|
||||
match stake_account.state().ok() {
|
||||
Some(stake_state) => (*stake_pubkey, (stake_state, stake_account)),
|
||||
None => {
|
||||
invalid_stake_keys
|
||||
.insert(*stake_pubkey, InvalidCacheEntryReason::BadState);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
let stake_account = match self.get_account_with_fixed_root(stake_pubkey) {
|
||||
Some(stake_account) => stake_account,
|
||||
None => {
|
||||
invalid_stake_keys
|
||||
.insert(*stake_pubkey, InvalidCacheEntryReason::Missing);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
let stake_account = match StakeAccount::try_from(stake_account) {
|
||||
Ok(stake_account) => stake_account,
|
||||
Err(stake_account::Error::InvalidOwner { .. }) => {
|
||||
invalid_stake_keys
|
||||
.insert(*stake_pubkey, InvalidCacheEntryReason::WrongOwner);
|
||||
return;
|
||||
}
|
||||
Err(stake_account::Error::InstructionError(_)) => {
|
||||
invalid_stake_keys
|
||||
.insert(*stake_pubkey, InvalidCacheEntryReason::BadState);
|
||||
return;
|
||||
}
|
||||
};
|
||||
let stake_delegation = (*stake_pubkey, stake_account);
|
||||
let mut vote_delegations = if let Some(vote_delegations) =
|
||||
vote_with_stake_delegations_map.get_mut(vote_pubkey)
|
||||
{
|
||||
|
@ -2754,9 +2752,9 @@ impl Bank {
|
|||
|
||||
delegations
|
||||
.par_iter()
|
||||
.map(|(_stake_pubkey, (stake_state, _stake_account))| {
|
||||
.map(|(_stake_pubkey, stake_account)| {
|
||||
stake_state::calculate_points(
|
||||
stake_state,
|
||||
stake_account.stake_state(),
|
||||
vote_state,
|
||||
Some(&stake_history),
|
||||
)
|
||||
|
@ -2797,66 +2795,62 @@ impl Bank {
|
|||
let mut m = Measure::start("redeem_rewards");
|
||||
let mut stake_rewards = thread_pool.install(|| {
|
||||
stake_delegation_iterator
|
||||
.filter_map(
|
||||
|(
|
||||
vote_pubkey,
|
||||
vote_state,
|
||||
(stake_pubkey, (stake_state, mut stake_account)),
|
||||
)| {
|
||||
// curry closure to add the contextual stake_pubkey
|
||||
let reward_calc_tracer = reward_calc_tracer.as_ref().map(|outer| {
|
||||
// inner
|
||||
move |inner_event: &_| {
|
||||
outer(&RewardCalculationEvent::Staking(&stake_pubkey, inner_event))
|
||||
}
|
||||
});
|
||||
let redeemed = stake_state::redeem_rewards(
|
||||
rewarded_epoch,
|
||||
stake_state,
|
||||
&mut stake_account,
|
||||
&vote_state,
|
||||
&point_value,
|
||||
Some(&stake_history),
|
||||
reward_calc_tracer.as_ref(),
|
||||
fix_activating_credits_observed,
|
||||
);
|
||||
if let Ok((stakers_reward, voters_reward)) = redeemed {
|
||||
// track voter rewards
|
||||
if let Some((
|
||||
_vote_account,
|
||||
_commission,
|
||||
vote_rewards_sum,
|
||||
vote_needs_store,
|
||||
)) = vote_account_rewards.get_mut(&vote_pubkey).as_deref_mut()
|
||||
{
|
||||
*vote_needs_store = true;
|
||||
*vote_rewards_sum = vote_rewards_sum.saturating_add(voters_reward);
|
||||
}
|
||||
|
||||
// store stake account even if stakers_reward is 0
|
||||
// because credits observed has changed
|
||||
self.store_account(&stake_pubkey, &stake_account);
|
||||
|
||||
if stakers_reward > 0 {
|
||||
return Some((
|
||||
stake_pubkey,
|
||||
RewardInfo {
|
||||
reward_type: RewardType::Staking,
|
||||
lamports: stakers_reward as i64,
|
||||
post_balance: stake_account.lamports(),
|
||||
commission: Some(vote_state.commission),
|
||||
},
|
||||
));
|
||||
}
|
||||
} else {
|
||||
debug!(
|
||||
"stake_state::redeem_rewards() failed for {}: {:?}",
|
||||
stake_pubkey, redeemed
|
||||
);
|
||||
.filter_map(|(vote_pubkey, vote_state, (stake_pubkey, stake_account))| {
|
||||
// curry closure to add the contextual stake_pubkey
|
||||
let reward_calc_tracer = reward_calc_tracer.as_ref().map(|outer| {
|
||||
// inner
|
||||
move |inner_event: &_| {
|
||||
outer(&RewardCalculationEvent::Staking(&stake_pubkey, inner_event))
|
||||
}
|
||||
None
|
||||
},
|
||||
)
|
||||
});
|
||||
let (mut stake_account, stake_state) =
|
||||
<(AccountSharedData, StakeState)>::from(stake_account);
|
||||
let redeemed = stake_state::redeem_rewards(
|
||||
rewarded_epoch,
|
||||
stake_state,
|
||||
&mut stake_account,
|
||||
&vote_state,
|
||||
&point_value,
|
||||
Some(&stake_history),
|
||||
reward_calc_tracer.as_ref(),
|
||||
fix_activating_credits_observed,
|
||||
);
|
||||
if let Ok((stakers_reward, voters_reward)) = redeemed {
|
||||
// track voter rewards
|
||||
if let Some((
|
||||
_vote_account,
|
||||
_commission,
|
||||
vote_rewards_sum,
|
||||
vote_needs_store,
|
||||
)) = vote_account_rewards.get_mut(&vote_pubkey).as_deref_mut()
|
||||
{
|
||||
*vote_needs_store = true;
|
||||
*vote_rewards_sum = vote_rewards_sum.saturating_add(voters_reward);
|
||||
}
|
||||
|
||||
// store stake account even if stakers_reward is 0
|
||||
// because credits observed has changed
|
||||
self.store_account(&stake_pubkey, &stake_account);
|
||||
|
||||
if stakers_reward > 0 {
|
||||
return Some((
|
||||
stake_pubkey,
|
||||
RewardInfo {
|
||||
reward_type: RewardType::Staking,
|
||||
lamports: stakers_reward as i64,
|
||||
post_balance: stake_account.lamports(),
|
||||
commission: Some(vote_state.commission),
|
||||
},
|
||||
));
|
||||
}
|
||||
} else {
|
||||
debug!(
|
||||
"stake_state::redeem_rewards() failed for {}: {:?}",
|
||||
stake_pubkey, redeemed
|
||||
);
|
||||
}
|
||||
None
|
||||
})
|
||||
.collect()
|
||||
});
|
||||
m.stop();
|
||||
|
@ -9084,9 +9078,13 @@ pub(crate) mod tests {
|
|||
)| {
|
||||
delegations
|
||||
.iter()
|
||||
.map(move |(_stake_pubkey, (stake_state, _stake_account))| {
|
||||
stake_state::calculate_points(stake_state, &vote_state, None)
|
||||
.unwrap_or(0)
|
||||
.map(move |(_stake_pubkey, stake_account)| {
|
||||
stake_state::calculate_points(
|
||||
stake_account.stake_state(),
|
||||
&vote_state,
|
||||
None, // stake_history
|
||||
)
|
||||
.unwrap_or_default()
|
||||
})
|
||||
.sum::<u128>()
|
||||
},
|
||||
|
|
|
@ -59,6 +59,7 @@ pub mod snapshot_hash;
|
|||
pub mod snapshot_package;
|
||||
pub mod snapshot_utils;
|
||||
pub mod sorted_storages;
|
||||
mod stake_account;
|
||||
pub mod stake_history;
|
||||
pub mod stake_weighted_timestamp;
|
||||
pub mod stakes;
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
use {
|
||||
solana_sdk::{
|
||||
account::{AccountSharedData, ReadableAccount},
|
||||
account_utils::StateMut,
|
||||
instruction::InstructionError,
|
||||
pubkey::Pubkey,
|
||||
stake::state::StakeState,
|
||||
},
|
||||
thiserror::Error,
|
||||
};
|
||||
|
||||
/// An account and a stake state deserialized from the account.
|
||||
#[derive(Clone, Debug, Default, PartialEq)]
|
||||
pub(crate) struct StakeAccount(AccountSharedData, StakeState);
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub(crate) enum Error {
|
||||
#[error(transparent)]
|
||||
InstructionError(#[from] InstructionError),
|
||||
#[error("Invalid stake account owner: {owner:?}")]
|
||||
InvalidOwner { owner: Pubkey },
|
||||
}
|
||||
|
||||
impl StakeAccount {
|
||||
#[inline]
|
||||
pub(crate) fn stake_state(&self) -> &StakeState {
|
||||
&self.1
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<AccountSharedData> for StakeAccount {
|
||||
type Error = Error;
|
||||
fn try_from(account: AccountSharedData) -> Result<Self, Self::Error> {
|
||||
if account.owner() != &solana_stake_program::id() {
|
||||
return Err(Error::InvalidOwner {
|
||||
owner: *account.owner(),
|
||||
});
|
||||
}
|
||||
let stake_state = account.state()?;
|
||||
Ok(Self(account, stake_state))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<StakeAccount> for (AccountSharedData, StakeState) {
|
||||
fn from(stake_account: StakeAccount) -> Self {
|
||||
(stake_account.0, stake_account.1)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue