diff --git a/Cargo.lock b/Cargo.lock index 584ba7177d..c371bee8fc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5001,6 +5001,7 @@ dependencies = [ "bytecount", "clap 2.33.3", "csv", + "dashmap", "histogram", "itertools 0.10.1", "log 0.4.14", diff --git a/ledger-tool/Cargo.toml b/ledger-tool/Cargo.toml index 936d45955b..700489fc45 100644 --- a/ledger-tool/Cargo.toml +++ b/ledger-tool/Cargo.toml @@ -14,6 +14,7 @@ bs58 = "0.4.0" bytecount = "0.6.2" clap = "2.33.1" csv = "1.1.6" +dashmap = "4.0.2" histogram = "*" itertools = "0.10.1" log = { version = "0.4.14" } diff --git a/ledger-tool/src/main.rs b/ledger-tool/src/main.rs index d12b1916d3..1c47116a4f 100644 --- a/ledger-tool/src/main.rs +++ b/ledger-tool/src/main.rs @@ -3,6 +3,7 @@ use clap::{ crate_description, crate_name, value_t, value_t_or_exit, values_t_or_exit, App, AppSettings, Arg, ArgMatches, SubCommand, }; +use dashmap::DashMap; use itertools::Itertools; use log::*; use regex::Regex; @@ -2547,15 +2548,16 @@ fn main() { skipped_reasons: String, } use solana_stake_program::stake_state::InflationPointCalculationEvent; - let mut stake_calcuration_details: HashMap = - HashMap::new(); - let mut last_point_value = None; + let stake_calculation_details: DashMap = + DashMap::new(); + let last_point_value = Arc::new(RwLock::new(None)); let tracer = |event: &RewardCalculationEvent| { // Currently RewardCalculationEvent enum has only Staking variant // because only staking tracing is supported! #[allow(irrefutable_let_patterns)] if let RewardCalculationEvent::Staking(pubkey, event) = event { - let detail = stake_calcuration_details.entry(**pubkey).or_default(); + let mut detail = + stake_calculation_details.entry(**pubkey).or_default(); match event { InflationPointCalculationEvent::CalculatedPoints( epoch, @@ -2580,12 +2582,11 @@ fn main() { detail.point_value = Some(point_value.clone()); // we have duplicate copies of `PointValue`s for possible // miscalculation; do some minimum sanity check - let point_value = detail.point_value.clone(); - if point_value.is_some() { - if last_point_value.is_some() { - assert_eq!(last_point_value, point_value,); - } - last_point_value = point_value; + let mut last_point_value = last_point_value.write().unwrap(); + if let Some(last_point_value) = last_point_value.as_ref() { + assert_eq!(last_point_value, point_value); + } else { + *last_point_value = Some(point_value.clone()); } } InflationPointCalculationEvent::EffectiveStakeAtRewardedEpoch(stake) => { @@ -2690,16 +2691,17 @@ fn main() { }, ); - let mut unchanged_accounts = stake_calcuration_details - .keys() + let mut unchanged_accounts = stake_calculation_details + .iter() + .map(|entry| *entry.key()) .collect::>() .difference( &rewarded_accounts .iter() - .map(|(pubkey, ..)| *pubkey) + .map(|(pubkey, ..)| **pubkey) .collect(), ) - .map(|pubkey| (**pubkey, warped_bank.get_account(pubkey).unwrap())) + .map(|pubkey| (*pubkey, warped_bank.get_account(pubkey).unwrap())) .collect::>(); unchanged_accounts.sort_unstable_by_key(|(pubkey, account)| { (*account.owner(), account.lamports(), *pubkey) @@ -2720,7 +2722,9 @@ fn main() { if let Some(base_account) = base_bank.get_account(&pubkey) { let delta = warped_account.lamports() - base_account.lamports(); - let detail = stake_calcuration_details.get(&pubkey); + let detail_ref = stake_calculation_details.get(&pubkey); + let detail: Option<&CalculationDetail> = + detail_ref.as_ref().map(|detail_ref| detail_ref.value()); println!( "{:<45}({}): {} => {} (+{} {:>4.9}%) {:?}", format!("{}", pubkey), // format! is needed to pad/justify correctly. @@ -2843,10 +2847,18 @@ fn main() { ), commission: format_or_na(detail.map(|d| d.commission)), cluster_rewards: format_or_na( - last_point_value.as_ref().map(|pv| pv.rewards), + last_point_value + .read() + .unwrap() + .clone() + .map(|pv| pv.rewards), ), cluster_points: format_or_na( - last_point_value.as_ref().map(|pv| pv.points), + last_point_value + .read() + .unwrap() + .clone() + .map(|pv| pv.points), ), old_capitalization: base_bank.capitalization(), new_capitalization: warped_bank.capitalization(), diff --git a/programs/stake/src/stake_state.rs b/programs/stake/src/stake_state.rs index a7044ee182..cff0e0ebb7 100644 --- a/programs/stake/src/stake_state.rs +++ b/programs/stake/src/stake_state.rs @@ -59,7 +59,7 @@ pub enum InflationPointCalculationEvent { Skipped(SkippedReason), } -pub(crate) fn null_tracer() -> Option { +pub(crate) fn null_tracer() -> Option { None:: } @@ -161,10 +161,10 @@ fn redeem_stake_rewards( point_value: &PointValue, vote_state: &VoteState, stake_history: Option<&StakeHistory>, - inflation_point_calc_tracer: &mut Option, + inflation_point_calc_tracer: Option, fix_activating_credits_observed: bool, ) -> 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.as_ref() { inflation_point_calc_tracer(&InflationPointCalculationEvent::CreditsObserved( stake.credits_observed, None, @@ -176,7 +176,7 @@ fn redeem_stake_rewards( point_value, vote_state, stake_history, - inflation_point_calc_tracer, + inflation_point_calc_tracer.as_ref(), fix_activating_credits_observed, ) .map(|(stakers_reward, voters_reward, credits_observed)| { @@ -196,7 +196,7 @@ fn calculate_stake_points( stake: &Stake, vote_state: &VoteState, stake_history: Option<&StakeHistory>, - inflation_point_calc_tracer: &mut Option, + inflation_point_calc_tracer: Option, ) -> u128 { calculate_stake_points_and_credits( stake, @@ -214,11 +214,11 @@ fn calculate_stake_points_and_credits( stake: &Stake, new_vote_state: &VoteState, stake_history: Option<&StakeHistory>, - inflation_point_calc_tracer: &mut Option, + inflation_point_calc_tracer: Option, ) -> (u128, u64) { // if there is no newer credits since observed, return no point if new_vote_state.credits() <= stake.credits_observed { - if let Some(inflation_point_calc_tracer) = inflation_point_calc_tracer { + if let Some(inflation_point_calc_tracer) = inflation_point_calc_tracer.as_ref() { inflation_point_calc_tracer(&SkippedReason::ZeroCreditsAndReturnCurrent.into()); } return (0, stake.credits_observed); @@ -254,7 +254,7 @@ fn calculate_stake_points_and_credits( let earned_points = stake_amount * earned_credits; points += earned_points; - if let Some(inflation_point_calc_tracer) = inflation_point_calc_tracer { + if let Some(inflation_point_calc_tracer) = inflation_point_calc_tracer.as_ref() { inflation_point_calc_tracer(&InflationPointCalculationEvent::CalculatedPoints( epoch, stake_amount, @@ -279,14 +279,14 @@ fn calculate_stake_rewards( point_value: &PointValue, vote_state: &VoteState, stake_history: Option<&StakeHistory>, - inflation_point_calc_tracer: &mut Option, + inflation_point_calc_tracer: Option, fix_activating_credits_observed: bool, ) -> Option<(u64, u64, u64)> { let (points, credits_observed) = calculate_stake_points_and_credits( stake, vote_state, stake_history, - inflation_point_calc_tracer, + inflation_point_calc_tracer.as_ref(), ); // Drive credits_observed forward unconditionally when rewards are disabled @@ -1105,11 +1105,11 @@ pub fn redeem_rewards( vote_state: &VoteState, point_value: &PointValue, stake_history: Option<&StakeHistory>, - inflation_point_calc_tracer: &mut Option, + inflation_point_calc_tracer: Option, fix_activating_credits_observed: bool, ) -> Result<(u64, u64), InstructionError> { 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.as_ref() { inflation_point_calc_tracer( &InflationPointCalculationEvent::EffectiveStakeAtRewardedEpoch( stake.stake(rewarded_epoch, stake_history), @@ -1160,7 +1160,7 @@ pub fn calculate_points( &stake, &vote_state, stake_history, - &mut null_tracer(), + null_tracer(), )) } else { Err(InstructionError::InvalidAccountData) @@ -3393,7 +3393,7 @@ mod tests { }, &vote_state, None, - &mut null_tracer(), + null_tracer(), true, ) ); @@ -3414,7 +3414,7 @@ mod tests { }, &vote_state, None, - &mut null_tracer(), + null_tracer(), true, ) ); @@ -3452,7 +3452,7 @@ mod tests { }, &vote_state, None, - &mut null_tracer(), + null_tracer(), true, ) ); @@ -3467,7 +3467,7 @@ mod tests { // no overflow on points assert_eq!( u128::from(stake.delegation.stake) * epoch_slots, - calculate_stake_points(&stake, &vote_state, None, &mut null_tracer()) + calculate_stake_points(&stake, &vote_state, None, null_tracer()) ); } @@ -3496,7 +3496,7 @@ mod tests { }, &vote_state, None, - &mut null_tracer(), + null_tracer(), true, ) ); @@ -3517,7 +3517,7 @@ mod tests { }, &vote_state, None, - &mut null_tracer(), + null_tracer(), true, ) ); @@ -3535,7 +3535,7 @@ mod tests { }, &vote_state, None, - &mut null_tracer(), + null_tracer(), true, ) ); @@ -3556,7 +3556,7 @@ mod tests { }, &vote_state, None, - &mut null_tracer(), + null_tracer(), true, ) ); @@ -3575,7 +3575,7 @@ mod tests { }, &vote_state, None, - &mut null_tracer(), + null_tracer(), true, ) ); @@ -3600,7 +3600,7 @@ mod tests { }, &vote_state, None, - &mut null_tracer(), + null_tracer(), true, ) ); @@ -3619,7 +3619,7 @@ mod tests { }, &vote_state, None, - &mut null_tracer(), + null_tracer(), true, ) ); @@ -3635,7 +3635,7 @@ mod tests { }, &vote_state, None, - &mut null_tracer(), + null_tracer(), true, ) ); @@ -3654,7 +3654,7 @@ mod tests { }, &vote_state, None, - &mut null_tracer(), + null_tracer(), true, ) ); @@ -3673,7 +3673,7 @@ mod tests { }, &vote_state, None, - &mut null_tracer(), + null_tracer(), true, ) ); @@ -3681,7 +3681,7 @@ mod tests { // assert the previous behavior is preserved where fix_stake_deactivate=false assert_eq!( (0, 4), - calculate_stake_points_and_credits(&stake, &vote_state, None, &mut null_tracer()) + calculate_stake_points_and_credits(&stake, &vote_state, None, null_tracer()) ); // get rewards and credits observed when not the activation epoch @@ -3703,7 +3703,7 @@ mod tests { }, &vote_state, None, - &mut null_tracer(), + null_tracer(), true, ) ); @@ -3723,7 +3723,7 @@ mod tests { }, &vote_state, None, - &mut null_tracer(), + null_tracer(), true, ) ); diff --git a/runtime/src/bank.rs b/runtime/src/bank.rs index 3a92d50b96..a787fb2bce 100644 --- a/runtime/src/bank.rs +++ b/runtime/src/bank.rs @@ -789,7 +789,7 @@ pub enum RewardCalculationEvent<'a, 'b> { Staking(&'a Pubkey, &'b InflationPointCalculationEvent), } -fn null_tracer() -> Option { +fn null_tracer() -> Option { None:: } @@ -1228,7 +1228,7 @@ impl Bank { /// Create a new bank that points to an immutable checkpoint of another bank. pub fn new_from_parent(parent: &Arc, collector_id: &Pubkey, slot: Slot) -> Self { - Self::_new_from_parent(parent, collector_id, slot, &mut null_tracer(), false) + Self::_new_from_parent(parent, collector_id, slot, null_tracer(), false) } pub fn new_from_parent_with_vote_only( @@ -1237,35 +1237,23 @@ impl Bank { slot: Slot, vote_only_bank: bool, ) -> Self { - Self::_new_from_parent( - parent, - collector_id, - slot, - &mut null_tracer(), - vote_only_bank, - ) + Self::_new_from_parent(parent, collector_id, slot, null_tracer(), vote_only_bank) } pub fn new_from_parent_with_tracer( parent: &Arc, collector_id: &Pubkey, slot: Slot, - reward_calc_tracer: impl FnMut(&RewardCalculationEvent), + reward_calc_tracer: impl Fn(&RewardCalculationEvent) + Send + Sync, ) -> Self { - Self::_new_from_parent( - parent, - collector_id, - slot, - &mut Some(reward_calc_tracer), - false, - ) + Self::_new_from_parent(parent, collector_id, slot, Some(reward_calc_tracer), false) } fn _new_from_parent( parent: &Arc, collector_id: &Pubkey, slot: Slot, - reward_calc_tracer: &mut Option, + reward_calc_tracer: Option, vote_only_bank: bool, ) -> Self { parent.freeze(); @@ -1949,7 +1937,7 @@ impl Bank { fn update_rewards( &mut self, prev_epoch: Epoch, - reward_calc_tracer: &mut Option, + reward_calc_tracer: Option, ) { if prev_epoch == self.epoch() { return; @@ -2053,7 +2041,7 @@ impl Bank { /// Filters out invalid pairs fn stake_delegation_accounts( &self, - reward_calc_tracer: &mut Option, + reward_calc_tracer: Option, ) -> HashMap, AccountSharedData)> { let mut accounts = HashMap::new(); @@ -2069,7 +2057,7 @@ impl Bank { ) { (Some(stake_account), Some(vote_account)) => { // call tracer to catch any illegal data if any - if let Some(reward_calc_tracer) = reward_calc_tracer { + if let Some(reward_calc_tracer) = reward_calc_tracer.as_ref() { reward_calc_tracer(&RewardCalculationEvent::Staking( stake_pubkey, &InflationPointCalculationEvent::Delegation( @@ -2114,12 +2102,13 @@ impl Bank { &mut self, rewarded_epoch: Epoch, rewards: u64, - reward_calc_tracer: &mut Option, + reward_calc_tracer: Option, fix_activating_credits_observed: bool, ) -> f64 { let stake_history = self.stakes.read().unwrap().history().clone(); - let mut stake_delegation_accounts = self.stake_delegation_accounts(reward_calc_tracer); + let mut stake_delegation_accounts = + self.stake_delegation_accounts(reward_calc_tracer.as_ref()); let points: u128 = stake_delegation_accounts .iter() @@ -2159,7 +2148,7 @@ impl Bank { for (stake_pubkey, stake_account) in stake_group.iter_mut() { // curry closure to add the contextual stake_pubkey - let mut reward_calc_tracer = reward_calc_tracer.as_mut().map(|outer| { + let reward_calc_tracer = reward_calc_tracer.as_ref().map(|outer| { let stake_pubkey = *stake_pubkey; // inner move |inner_event: &_| { @@ -2173,7 +2162,7 @@ impl Bank { &vote_state, &point_value, Some(&stake_history), - &mut reward_calc_tracer.as_mut(), + reward_calc_tracer, fix_activating_credits_observed, ); if let Ok((stakers_reward, _voters_reward)) = redeemed { @@ -7843,7 +7832,7 @@ pub(crate) mod tests { bank0.store_account_and_update_capitalization(&vote_id, &vote_account); let validator_points: u128 = bank0 - .stake_delegation_accounts(&mut null_tracer()) + .stake_delegation_accounts(null_tracer()) .iter() .flat_map(|(_vote_pubkey, (stake_group, vote_account))| { stake_group @@ -13868,7 +13857,7 @@ pub(crate) mod tests { vec![10_000; 2], ); let bank = Arc::new(Bank::new_for_tests(&genesis_config)); - let stake_delegation_accounts = bank.stake_delegation_accounts(&mut null_tracer()); + let stake_delegation_accounts = bank.stake_delegation_accounts(null_tracer()); assert_eq!(stake_delegation_accounts.len(), 2); let mut vote_account = bank @@ -13907,7 +13896,7 @@ pub(crate) mod tests { ); // Accounts must be valid stake and vote accounts - let stake_delegation_accounts = bank.stake_delegation_accounts(&mut null_tracer()); + let stake_delegation_accounts = bank.stake_delegation_accounts(null_tracer()); assert_eq!(stake_delegation_accounts.len(), 0); }