Make rewards tracer async friendly (#20452)

This commit is contained in:
Justin Starry 2021-10-05 21:30:08 -04:00 committed by GitHub
parent 18e47ab9f9
commit 250a8503fe
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 78 additions and 75 deletions

1
Cargo.lock generated
View File

@ -5001,6 +5001,7 @@ dependencies = [
"bytecount", "bytecount",
"clap 2.33.3", "clap 2.33.3",
"csv", "csv",
"dashmap",
"histogram", "histogram",
"itertools 0.10.1", "itertools 0.10.1",
"log 0.4.14", "log 0.4.14",

View File

@ -14,6 +14,7 @@ bs58 = "0.4.0"
bytecount = "0.6.2" bytecount = "0.6.2"
clap = "2.33.1" clap = "2.33.1"
csv = "1.1.6" csv = "1.1.6"
dashmap = "4.0.2"
histogram = "*" histogram = "*"
itertools = "0.10.1" itertools = "0.10.1"
log = { version = "0.4.14" } log = { version = "0.4.14" }

View File

@ -3,6 +3,7 @@ use clap::{
crate_description, crate_name, value_t, value_t_or_exit, values_t_or_exit, App, AppSettings, crate_description, crate_name, value_t, value_t_or_exit, values_t_or_exit, App, AppSettings,
Arg, ArgMatches, SubCommand, Arg, ArgMatches, SubCommand,
}; };
use dashmap::DashMap;
use itertools::Itertools; use itertools::Itertools;
use log::*; use log::*;
use regex::Regex; use regex::Regex;
@ -2547,15 +2548,16 @@ fn main() {
skipped_reasons: String, skipped_reasons: String,
} }
use solana_stake_program::stake_state::InflationPointCalculationEvent; use solana_stake_program::stake_state::InflationPointCalculationEvent;
let mut stake_calcuration_details: HashMap<Pubkey, CalculationDetail> = let stake_calculation_details: DashMap<Pubkey, CalculationDetail> =
HashMap::new(); DashMap::new();
let mut last_point_value = None; let last_point_value = Arc::new(RwLock::new(None));
let tracer = |event: &RewardCalculationEvent| { let tracer = |event: &RewardCalculationEvent| {
// Currently RewardCalculationEvent enum has only Staking variant // Currently RewardCalculationEvent enum has only Staking variant
// because only staking tracing is supported! // because only staking tracing is supported!
#[allow(irrefutable_let_patterns)] #[allow(irrefutable_let_patterns)]
if let RewardCalculationEvent::Staking(pubkey, event) = event { 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 { match event {
InflationPointCalculationEvent::CalculatedPoints( InflationPointCalculationEvent::CalculatedPoints(
epoch, epoch,
@ -2580,12 +2582,11 @@ fn main() {
detail.point_value = Some(point_value.clone()); detail.point_value = Some(point_value.clone());
// we have duplicate copies of `PointValue`s for possible // we have duplicate copies of `PointValue`s for possible
// miscalculation; do some minimum sanity check // miscalculation; do some minimum sanity check
let point_value = detail.point_value.clone(); let mut last_point_value = last_point_value.write().unwrap();
if point_value.is_some() { if let Some(last_point_value) = last_point_value.as_ref() {
if last_point_value.is_some() { assert_eq!(last_point_value, point_value);
assert_eq!(last_point_value, point_value,); } else {
} *last_point_value = Some(point_value.clone());
last_point_value = point_value;
} }
} }
InflationPointCalculationEvent::EffectiveStakeAtRewardedEpoch(stake) => { InflationPointCalculationEvent::EffectiveStakeAtRewardedEpoch(stake) => {
@ -2690,16 +2691,17 @@ fn main() {
}, },
); );
let mut unchanged_accounts = stake_calcuration_details let mut unchanged_accounts = stake_calculation_details
.keys() .iter()
.map(|entry| *entry.key())
.collect::<HashSet<_>>() .collect::<HashSet<_>>()
.difference( .difference(
&rewarded_accounts &rewarded_accounts
.iter() .iter()
.map(|(pubkey, ..)| *pubkey) .map(|(pubkey, ..)| **pubkey)
.collect(), .collect(),
) )
.map(|pubkey| (**pubkey, warped_bank.get_account(pubkey).unwrap())) .map(|pubkey| (*pubkey, warped_bank.get_account(pubkey).unwrap()))
.collect::<Vec<_>>(); .collect::<Vec<_>>();
unchanged_accounts.sort_unstable_by_key(|(pubkey, account)| { unchanged_accounts.sort_unstable_by_key(|(pubkey, account)| {
(*account.owner(), account.lamports(), *pubkey) (*account.owner(), account.lamports(), *pubkey)
@ -2720,7 +2722,9 @@ fn main() {
if let Some(base_account) = base_bank.get_account(&pubkey) { if let Some(base_account) = base_bank.get_account(&pubkey) {
let delta = warped_account.lamports() - base_account.lamports(); 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!( println!(
"{:<45}({}): {} => {} (+{} {:>4.9}%) {:?}", "{:<45}({}): {} => {} (+{} {:>4.9}%) {:?}",
format!("{}", pubkey), // format! is needed to pad/justify correctly. format!("{}", pubkey), // format! is needed to pad/justify correctly.
@ -2843,10 +2847,18 @@ fn main() {
), ),
commission: format_or_na(detail.map(|d| d.commission)), commission: format_or_na(detail.map(|d| d.commission)),
cluster_rewards: format_or_na( 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( 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(), old_capitalization: base_bank.capitalization(),
new_capitalization: warped_bank.capitalization(), new_capitalization: warped_bank.capitalization(),

View File

@ -59,7 +59,7 @@ pub enum InflationPointCalculationEvent {
Skipped(SkippedReason), Skipped(SkippedReason),
} }
pub(crate) fn null_tracer() -> Option<impl FnMut(&InflationPointCalculationEvent)> { pub(crate) fn null_tracer() -> Option<impl Fn(&InflationPointCalculationEvent)> {
None::<fn(&_)> None::<fn(&_)>
} }
@ -161,10 +161,10 @@ fn redeem_stake_rewards(
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: Option<impl Fn(&InflationPointCalculationEvent)>,
fix_activating_credits_observed: bool, fix_activating_credits_observed: 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.as_ref() {
inflation_point_calc_tracer(&InflationPointCalculationEvent::CreditsObserved( inflation_point_calc_tracer(&InflationPointCalculationEvent::CreditsObserved(
stake.credits_observed, stake.credits_observed,
None, None,
@ -176,7 +176,7 @@ fn redeem_stake_rewards(
point_value, point_value,
vote_state, vote_state,
stake_history, stake_history,
inflation_point_calc_tracer, inflation_point_calc_tracer.as_ref(),
fix_activating_credits_observed, fix_activating_credits_observed,
) )
.map(|(stakers_reward, voters_reward, credits_observed)| { .map(|(stakers_reward, voters_reward, credits_observed)| {
@ -196,7 +196,7 @@ fn calculate_stake_points(
stake: &Stake, stake: &Stake,
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: Option<impl Fn(&InflationPointCalculationEvent)>,
) -> u128 { ) -> u128 {
calculate_stake_points_and_credits( calculate_stake_points_and_credits(
stake, stake,
@ -214,11 +214,11 @@ fn calculate_stake_points_and_credits(
stake: &Stake, stake: &Stake,
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: Option<impl Fn(&InflationPointCalculationEvent)>,
) -> (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 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()); inflation_point_calc_tracer(&SkippedReason::ZeroCreditsAndReturnCurrent.into());
} }
return (0, stake.credits_observed); return (0, stake.credits_observed);
@ -254,7 +254,7 @@ fn calculate_stake_points_and_credits(
let earned_points = stake_amount * earned_credits; let earned_points = stake_amount * earned_credits;
points += earned_points; 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( inflation_point_calc_tracer(&InflationPointCalculationEvent::CalculatedPoints(
epoch, epoch,
stake_amount, stake_amount,
@ -279,14 +279,14 @@ fn calculate_stake_rewards(
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: Option<impl Fn(&InflationPointCalculationEvent)>,
fix_activating_credits_observed: bool, fix_activating_credits_observed: 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.as_ref(),
); );
// Drive credits_observed forward unconditionally when rewards are disabled // Drive credits_observed forward unconditionally when rewards are disabled
@ -1105,11 +1105,11 @@ pub fn redeem_rewards(
vote_state: &VoteState, vote_state: &VoteState,
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: Option<impl Fn(&InflationPointCalculationEvent)>,
fix_activating_credits_observed: bool, fix_activating_credits_observed: 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.as_ref() {
inflation_point_calc_tracer( inflation_point_calc_tracer(
&InflationPointCalculationEvent::EffectiveStakeAtRewardedEpoch( &InflationPointCalculationEvent::EffectiveStakeAtRewardedEpoch(
stake.stake(rewarded_epoch, stake_history), stake.stake(rewarded_epoch, stake_history),
@ -1160,7 +1160,7 @@ pub fn calculate_points(
&stake, &stake,
&vote_state, &vote_state,
stake_history, stake_history,
&mut null_tracer(), null_tracer(),
)) ))
} else { } else {
Err(InstructionError::InvalidAccountData) Err(InstructionError::InvalidAccountData)
@ -3393,7 +3393,7 @@ mod tests {
}, },
&vote_state, &vote_state,
None, None,
&mut null_tracer(), null_tracer(),
true, true,
) )
); );
@ -3414,7 +3414,7 @@ mod tests {
}, },
&vote_state, &vote_state,
None, None,
&mut null_tracer(), null_tracer(),
true, true,
) )
); );
@ -3452,7 +3452,7 @@ mod tests {
}, },
&vote_state, &vote_state,
None, None,
&mut null_tracer(), null_tracer(),
true, true,
) )
); );
@ -3467,7 +3467,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()) calculate_stake_points(&stake, &vote_state, None, null_tracer())
); );
} }
@ -3496,7 +3496,7 @@ mod tests {
}, },
&vote_state, &vote_state,
None, None,
&mut null_tracer(), null_tracer(),
true, true,
) )
); );
@ -3517,7 +3517,7 @@ mod tests {
}, },
&vote_state, &vote_state,
None, None,
&mut null_tracer(), null_tracer(),
true, true,
) )
); );
@ -3535,7 +3535,7 @@ mod tests {
}, },
&vote_state, &vote_state,
None, None,
&mut null_tracer(), null_tracer(),
true, true,
) )
); );
@ -3556,7 +3556,7 @@ mod tests {
}, },
&vote_state, &vote_state,
None, None,
&mut null_tracer(), null_tracer(),
true, true,
) )
); );
@ -3575,7 +3575,7 @@ mod tests {
}, },
&vote_state, &vote_state,
None, None,
&mut null_tracer(), null_tracer(),
true, true,
) )
); );
@ -3600,7 +3600,7 @@ mod tests {
}, },
&vote_state, &vote_state,
None, None,
&mut null_tracer(), null_tracer(),
true, true,
) )
); );
@ -3619,7 +3619,7 @@ mod tests {
}, },
&vote_state, &vote_state,
None, None,
&mut null_tracer(), null_tracer(),
true, true,
) )
); );
@ -3635,7 +3635,7 @@ mod tests {
}, },
&vote_state, &vote_state,
None, None,
&mut null_tracer(), null_tracer(),
true, true,
) )
); );
@ -3654,7 +3654,7 @@ mod tests {
}, },
&vote_state, &vote_state,
None, None,
&mut null_tracer(), null_tracer(),
true, true,
) )
); );
@ -3673,7 +3673,7 @@ mod tests {
}, },
&vote_state, &vote_state,
None, None,
&mut null_tracer(), null_tracer(),
true, true,
) )
); );
@ -3681,7 +3681,7 @@ mod tests {
// assert the previous behavior is preserved where fix_stake_deactivate=false // assert the previous behavior is preserved where fix_stake_deactivate=false
assert_eq!( assert_eq!(
(0, 4), (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 // get rewards and credits observed when not the activation epoch
@ -3703,7 +3703,7 @@ mod tests {
}, },
&vote_state, &vote_state,
None, None,
&mut null_tracer(), null_tracer(),
true, true,
) )
); );
@ -3723,7 +3723,7 @@ mod tests {
}, },
&vote_state, &vote_state,
None, None,
&mut null_tracer(), null_tracer(),
true, true,
) )
); );

View File

@ -789,7 +789,7 @@ pub enum RewardCalculationEvent<'a, 'b> {
Staking(&'a Pubkey, &'b InflationPointCalculationEvent), Staking(&'a Pubkey, &'b InflationPointCalculationEvent),
} }
fn null_tracer() -> Option<impl FnMut(&RewardCalculationEvent)> { fn null_tracer() -> Option<impl Fn(&RewardCalculationEvent) + Send + Sync> {
None::<fn(&RewardCalculationEvent)> None::<fn(&RewardCalculationEvent)>
} }
@ -1228,7 +1228,7 @@ impl Bank {
/// Create a new bank that points to an immutable checkpoint of another bank. /// Create a new bank that points to an immutable checkpoint of another bank.
pub fn new_from_parent(parent: &Arc<Bank>, collector_id: &Pubkey, slot: Slot) -> Self { pub fn new_from_parent(parent: &Arc<Bank>, 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( pub fn new_from_parent_with_vote_only(
@ -1237,35 +1237,23 @@ impl Bank {
slot: Slot, slot: Slot,
vote_only_bank: bool, vote_only_bank: bool,
) -> Self { ) -> Self {
Self::_new_from_parent( Self::_new_from_parent(parent, collector_id, slot, null_tracer(), vote_only_bank)
parent,
collector_id,
slot,
&mut null_tracer(),
vote_only_bank,
)
} }
pub fn new_from_parent_with_tracer( pub fn new_from_parent_with_tracer(
parent: &Arc<Bank>, parent: &Arc<Bank>,
collector_id: &Pubkey, collector_id: &Pubkey,
slot: Slot, slot: Slot,
reward_calc_tracer: impl FnMut(&RewardCalculationEvent), reward_calc_tracer: impl Fn(&RewardCalculationEvent) + Send + Sync,
) -> Self { ) -> Self {
Self::_new_from_parent( Self::_new_from_parent(parent, collector_id, slot, Some(reward_calc_tracer), false)
parent,
collector_id,
slot,
&mut Some(reward_calc_tracer),
false,
)
} }
fn _new_from_parent( fn _new_from_parent(
parent: &Arc<Bank>, parent: &Arc<Bank>,
collector_id: &Pubkey, collector_id: &Pubkey,
slot: Slot, slot: Slot,
reward_calc_tracer: &mut Option<impl FnMut(&RewardCalculationEvent)>, reward_calc_tracer: Option<impl Fn(&RewardCalculationEvent) + Send + Sync>,
vote_only_bank: bool, vote_only_bank: bool,
) -> Self { ) -> Self {
parent.freeze(); parent.freeze();
@ -1949,7 +1937,7 @@ impl Bank {
fn update_rewards( fn update_rewards(
&mut self, &mut self,
prev_epoch: Epoch, prev_epoch: Epoch,
reward_calc_tracer: &mut Option<impl FnMut(&RewardCalculationEvent)>, reward_calc_tracer: Option<impl Fn(&RewardCalculationEvent) + Send + Sync>,
) { ) {
if prev_epoch == self.epoch() { if prev_epoch == self.epoch() {
return; return;
@ -2053,7 +2041,7 @@ impl Bank {
/// Filters out invalid pairs /// Filters out invalid pairs
fn stake_delegation_accounts( fn stake_delegation_accounts(
&self, &self,
reward_calc_tracer: &mut Option<impl FnMut(&RewardCalculationEvent)>, reward_calc_tracer: Option<impl Fn(&RewardCalculationEvent) + Send + Sync>,
) -> HashMap<Pubkey, (Vec<(Pubkey, AccountSharedData)>, AccountSharedData)> { ) -> HashMap<Pubkey, (Vec<(Pubkey, AccountSharedData)>, AccountSharedData)> {
let mut accounts = HashMap::new(); let mut accounts = HashMap::new();
@ -2069,7 +2057,7 @@ impl Bank {
) { ) {
(Some(stake_account), Some(vote_account)) => { (Some(stake_account), Some(vote_account)) => {
// call tracer to catch any illegal data if any // 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( reward_calc_tracer(&RewardCalculationEvent::Staking(
stake_pubkey, stake_pubkey,
&InflationPointCalculationEvent::Delegation( &InflationPointCalculationEvent::Delegation(
@ -2114,12 +2102,13 @@ impl Bank {
&mut self, &mut self,
rewarded_epoch: Epoch, rewarded_epoch: Epoch,
rewards: u64, rewards: u64,
reward_calc_tracer: &mut Option<impl FnMut(&RewardCalculationEvent)>, reward_calc_tracer: Option<impl Fn(&RewardCalculationEvent) + Send + Sync>,
fix_activating_credits_observed: bool, fix_activating_credits_observed: bool,
) -> f64 { ) -> f64 {
let stake_history = self.stakes.read().unwrap().history().clone(); 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 let points: u128 = stake_delegation_accounts
.iter() .iter()
@ -2159,7 +2148,7 @@ impl Bank {
for (stake_pubkey, stake_account) in stake_group.iter_mut() { for (stake_pubkey, stake_account) in stake_group.iter_mut() {
// curry closure to add the contextual stake_pubkey // 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; let stake_pubkey = *stake_pubkey;
// inner // inner
move |inner_event: &_| { move |inner_event: &_| {
@ -2173,7 +2162,7 @@ impl Bank {
&vote_state, &vote_state,
&point_value, &point_value,
Some(&stake_history), Some(&stake_history),
&mut reward_calc_tracer.as_mut(), reward_calc_tracer,
fix_activating_credits_observed, fix_activating_credits_observed,
); );
if let Ok((stakers_reward, _voters_reward)) = redeemed { 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); bank0.store_account_and_update_capitalization(&vote_id, &vote_account);
let validator_points: u128 = bank0 let validator_points: u128 = bank0
.stake_delegation_accounts(&mut null_tracer()) .stake_delegation_accounts(null_tracer())
.iter() .iter()
.flat_map(|(_vote_pubkey, (stake_group, vote_account))| { .flat_map(|(_vote_pubkey, (stake_group, vote_account))| {
stake_group stake_group
@ -13868,7 +13857,7 @@ pub(crate) mod tests {
vec![10_000; 2], vec![10_000; 2],
); );
let bank = Arc::new(Bank::new_for_tests(&genesis_config)); 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); assert_eq!(stake_delegation_accounts.len(), 2);
let mut vote_account = bank let mut vote_account = bank
@ -13907,7 +13896,7 @@ pub(crate) mod tests {
); );
// Accounts must be valid stake and vote accounts // 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); assert_eq!(stake_delegation_accounts.len(), 0);
} }