Enhance ledger-tool for multi-epoch rewards (#13837)

* Support ledger-tool for multi-epoch rewards

* nits

* Ensure not to skip some records in csv
This commit is contained in:
Ryo Onodera 2020-11-27 13:20:47 +09:00 committed by GitHub
parent 008b56e535
commit 6048342c57
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 184 additions and 105 deletions

View File

@ -2038,54 +2038,74 @@ fn main() {
.lazy_rent_collection
.store(true, std::sync::atomic::Ordering::Relaxed);
if arg_matches.is_present("enable_stake_program_v2")
&& !base_bank.stake_program_v2_enabled()
{
if arg_matches.is_present("enable_stake_program_v2") {
let feature_account_balance = std::cmp::max(
genesis_config.rent.minimum_balance(Feature::size_of()),
1,
);
base_bank.store_account(
&feature_set::stake_program_v2::id(),
&feature::create_account(
&Feature { activated_at: None },
feature_account_balance,
),
);
base_bank.store_account(
&feature_set::rewrite_stake::id(),
&feature::create_account(
&Feature { activated_at: None },
feature_account_balance,
),
);
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;
}
let mut store_failed_count = 0;
if base_bank
.get_account(&feature_set::secp256k1_program_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::secp256k1_program_enabled::id(),
&Account::default(),
);
} else {
store_failed_count += 1;
if force_enabled_count >= 1 {
if base_bank
.get_account(&feature_set::secp256k1_program_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::secp256k1_program_enabled::id(),
&Account::default(),
);
force_enabled_count -= 1;
} else {
store_failed_count += 1;
}
}
if base_bank
.get_account(&feature_set::instructions_sysvar_enabled::id())
.is_some()
{
base_bank.store_account(
&feature_set::instructions_sysvar_enabled::id(),
&Account::default(),
);
} 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(),
&Account::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.
@ -2103,16 +2123,23 @@ fn main() {
}
}
#[derive(Default, Debug)]
struct PointDetail {
epoch: Epoch,
points: u128,
stake: u128,
credits: u128,
}
#[derive(Default, Debug)]
struct CalculationDetail {
epochs: usize,
voter: Pubkey,
voter_owner: Pubkey,
point: u128,
stake: u128,
current_effective_stake: u64,
total_stake: u64,
rent_exempt_reserve: u64,
credits: u128,
points: Vec<PointDetail>,
base_rewards: u64,
commission: u8,
vote_rewards: u64,
@ -2120,7 +2147,8 @@ fn main() {
activation_epoch: Epoch,
deactivation_epoch: Option<Epoch>,
point_value: Option<PointValue>,
credits_observed: Option<u64>,
old_credits_observed: Option<u64>,
new_credits_observed: Option<u64>,
}
use solana_stake_program::stake_state::InflationPointCalculationEvent;
let mut stake_calcuration_details: HashMap<Pubkey, CalculationDetail> =
@ -2134,16 +2162,14 @@ fn main() {
let detail = stake_calcuration_details.entry(**pubkey).or_default();
match event {
InflationPointCalculationEvent::CalculatedPoints(
point,
epoch,
stake,
credits,
points,
) => {
// Don't sum for epochs where no credits are earned
if *credits > 0 {
if *points > 0 {
detail.epochs += 1;
detail.point += *point;
detail.stake += *stake;
detail.credits += *credits;
detail.points.push(PointDetail {epoch: *epoch, points: *points, stake: *stake, credits: *credits});
}
}
InflationPointCalculationEvent::SplitRewards(
@ -2166,6 +2192,9 @@ fn main() {
last_point_value = point_value;
}
}
InflationPointCalculationEvent::EffectiveStakeAtRewardedEpoch(stake) => {
detail.current_effective_stake = *stake;
}
InflationPointCalculationEvent::Commission(commission) => {
detail.commission = *commission;
}
@ -2173,9 +2202,11 @@ fn main() {
detail.rent_exempt_reserve = *reserve;
}
InflationPointCalculationEvent::CreditsObserved(
credits_observed,
old_credits_observed,
new_credits_observed,
) => {
detail.credits_observed = Some(*credits_observed);
detail.old_credits_observed = Some(*old_credits_observed);
detail.new_credits_observed = Some(*new_credits_observed);
}
InflationPointCalculationEvent::Delegation(
delegation,
@ -2316,8 +2347,12 @@ fn main() {
activation_epoch: String,
deactivation_epoch: String,
earned_epochs: String,
earned_credits: String,
credits_observed: String,
epoch: String,
epoch_credits: String,
epoch_points: String,
epoch_stake: String,
old_credits_observed: String,
new_credits_observed: String,
base_rewards: String,
stake_rewards: String,
vote_rewards: String,
@ -2331,53 +2366,82 @@ fn main() {
data.map(|data| format!("{}", data))
.unwrap_or_else(|| "N/A".to_owned())
};
let record = InflationRecord {
account: format!("{}", pubkey),
owner: format!("{}", base_account.owner),
old_balance: base_account.lamports,
new_balance: warped_account.lamports,
data_size: base_account.data.len(),
delegation: format_or_na(detail.map(|d| d.voter)),
delegation_owner: format_or_na(
detail.map(|d| d.voter_owner),
),
effective_stake: format_or_na(detail.map(|d| d.stake)),
delegated_stake: format_or_na(
detail.map(|d| d.total_stake),
),
rent_exempt_reserve: format_or_na(
detail.map(|d| d.rent_exempt_reserve),
),
activation_epoch: format_or_na(detail.map(|d| {
if d.activation_epoch < Epoch::max_value() {
d.activation_epoch
} else {
// bootstraped
0
}
})),
deactivation_epoch: format_or_na(
detail.and_then(|d| d.deactivation_epoch),
),
earned_epochs: format_or_na(detail.map(|d| d.epochs)),
earned_credits: format_or_na(detail.map(|d| d.credits)),
credits_observed: format_or_na(
detail.and_then(|d| d.credits_observed),
),
base_rewards: format_or_na(detail.map(|d| d.base_rewards)),
stake_rewards: format_or_na(
detail.map(|d| d.stake_rewards),
),
vote_rewards: format_or_na(detail.map(|d| d.vote_rewards)),
commission: format_or_na(detail.map(|d| d.commission)),
cluster_rewards: format_or_na(
last_point_value.as_ref().map(|pv| pv.rewards),
),
cluster_points: format_or_na(
last_point_value.as_ref().map(|pv| pv.points),
),
};
csv_writer.serialize(&record).unwrap();
let mut point_details = detail
.map(|d| d.points.iter().map(Some).collect::<Vec<_>>())
.unwrap_or_default();
// ensure to print even if there is no calculation/point detail
if point_details.is_empty() {
point_details.push(None);
}
for point_detail in point_details {
let record = InflationRecord {
account: format!("{}", pubkey),
owner: format!("{}", base_account.owner),
old_balance: base_account.lamports,
new_balance: warped_account.lamports,
data_size: base_account.data.len(),
delegation: format_or_na(detail.map(|d| d.voter)),
delegation_owner: format_or_na(
detail.map(|d| d.voter_owner),
),
effective_stake: format_or_na(
detail.map(|d| d.current_effective_stake),
),
delegated_stake: format_or_na(
detail.map(|d| d.total_stake),
),
rent_exempt_reserve: format_or_na(
detail.map(|d| d.rent_exempt_reserve),
),
activation_epoch: format_or_na(detail.map(|d| {
if d.activation_epoch < Epoch::max_value() {
d.activation_epoch
} else {
// bootstraped
0
}
})),
deactivation_epoch: format_or_na(
detail.and_then(|d| d.deactivation_epoch),
),
earned_epochs: format_or_na(detail.map(|d| d.epochs)),
epoch: format_or_na(point_detail.map(|d| d.epoch)),
epoch_credits: format_or_na(
point_detail.map(|d| d.credits),
),
epoch_points: format_or_na(
point_detail.map(|d| d.points),
),
epoch_stake: format_or_na(
point_detail.map(|d| d.stake),
),
old_credits_observed: format_or_na(
detail.and_then(|d| d.old_credits_observed),
),
new_credits_observed: format_or_na(
detail.and_then(|d| d.new_credits_observed),
),
base_rewards: format_or_na(
detail.map(|d| d.base_rewards),
),
stake_rewards: format_or_na(
detail.map(|d| d.stake_rewards),
),
vote_rewards: format_or_na(
detail.map(|d| d.vote_rewards),
),
commission: format_or_na(detail.map(|d| d.commission)),
cluster_rewards: format_or_na(
last_point_value.as_ref().map(|pv| pv.rewards),
),
cluster_points: format_or_na(
last_point_value.as_ref().map(|pv| pv.points),
),
};
csv_writer.serialize(&record).unwrap();
}
}
overall_delta += delta;
} else {

View File

@ -33,12 +33,13 @@ pub enum StakeState {
#[derive(Debug)]
pub enum InflationPointCalculationEvent {
CalculatedPoints(u128, u128, u128),
CalculatedPoints(u64, u128, u128, u128),
SplitRewards(u64, u64, u64, PointValue),
EffectiveStakeAtRewardedEpoch(u64),
RentExemptReserve(u64),
Delegation(Delegation, Pubkey),
Commission(u8),
CreditsObserved(u64),
CreditsObserved(u64, u64),
}
fn null_tracer() -> Option<impl FnMut(&InflationPointCalculationEvent)> {
@ -521,12 +522,13 @@ impl Stake {
fix_stake_deactivate,
)
.map(|(stakers_reward, voters_reward, credits_observed)| {
self.credits_observed = credits_observed;
if let Some(inflation_point_calc_tracer) = inflation_point_calc_tracer {
inflation_point_calc_tracer(&InflationPointCalculationEvent::CreditsObserved(
self.credits_observed,
credits_observed,
));
}
self.credits_observed = credits_observed;
self.delegation.stake += stakers_reward;
(stakers_reward, voters_reward)
})
@ -594,13 +596,15 @@ impl Stake {
new_credits_observed = new_credits_observed.max(final_epoch_credits);
// finally calculate points for this epoch
points += stake * earned_credits;
let earned_points = stake * earned_credits;
points += earned_points;
if let Some(inflation_point_calc_tracer) = inflation_point_calc_tracer {
inflation_point_calc_tracer(&InflationPointCalculationEvent::CalculatedPoints(
points,
epoch,
stake,
earned_credits,
earned_points,
));
}
}
@ -1298,6 +1302,7 @@ impl MergeKind {
// utility function, used by runtime
// returns a tuple of (stakers_reward,voters_reward)
pub fn redeem_rewards(
rewarded_epoch: Epoch,
stake_account: &mut Account,
vote_account: &mut Account,
point_value: &PointValue,
@ -1309,6 +1314,13 @@ pub fn redeem_rewards(
let vote_state: VoteState =
StateMut::<VoteStateVersions>::state(vote_account)?.convert_to_current();
if let Some(inflation_point_calc_tracer) = inflation_point_calc_tracer {
inflation_point_calc_tracer(
&InflationPointCalculationEvent::EffectiveStakeAtRewardedEpoch(stake.stake(
rewarded_epoch,
stake_history,
fix_stake_deactivate,
)),
);
inflation_point_calc_tracer(&InflationPointCalculationEvent::RentExemptReserve(
meta.rent_exempt_reserve,
));

View File

@ -1456,6 +1456,7 @@ impl Bank {
let old_vote_balance_and_staked = self.stakes.read().unwrap().vote_balance_and_staked();
let validator_point_value = self.pay_validator_rewards(
prev_epoch,
validator_rewards,
reward_calc_tracer,
self.stake_program_v2_enabled(),
@ -1574,6 +1575,7 @@ impl Bank {
/// successfully load and parse, return the lamport value of one point
fn pay_validator_rewards(
&mut self,
rewarded_epoch: Epoch,
rewards: u64,
reward_calc_tracer: &mut Option<impl FnMut(&RewardCalculationEvent)>,
fix_stake_deactivate: bool,
@ -1622,6 +1624,7 @@ impl Bank {
}
});
let redeemed = stake_state::redeem_rewards(
rewarded_epoch,
stake_account,
vote_account,
&point_value,