* Support ledger-tool for multi-epoch rewards
* nits
* Ensure not to skip some records in csv
(cherry picked from commit 6048342c57
)
Co-authored-by: Ryo Onodera <ryoqun@gmail.com>
This commit is contained in:
@ -2038,54 +2038,74 @@ fn main() {
|
|||||||
.lazy_rent_collection
|
.lazy_rent_collection
|
||||||
.store(true, std::sync::atomic::Ordering::Relaxed);
|
.store(true, std::sync::atomic::Ordering::Relaxed);
|
||||||
|
|
||||||
if arg_matches.is_present("enable_stake_program_v2")
|
if arg_matches.is_present("enable_stake_program_v2") {
|
||||||
&& !base_bank.stake_program_v2_enabled()
|
|
||||||
{
|
|
||||||
let feature_account_balance = std::cmp::max(
|
let feature_account_balance = std::cmp::max(
|
||||||
genesis_config.rent.minimum_balance(Feature::size_of()),
|
genesis_config.rent.minimum_balance(Feature::size_of()),
|
||||||
1,
|
1,
|
||||||
);
|
);
|
||||||
base_bank.store_account(
|
let mut force_enabled_count = 0;
|
||||||
&feature_set::stake_program_v2::id(),
|
if base_bank
|
||||||
&feature::create_account(
|
.get_account(&feature_set::stake_program_v2::id())
|
||||||
&Feature { activated_at: None },
|
.is_none()
|
||||||
feature_account_balance,
|
{
|
||||||
),
|
base_bank.store_account(
|
||||||
);
|
&feature_set::stake_program_v2::id(),
|
||||||
base_bank.store_account(
|
&feature::create_account(
|
||||||
&feature_set::rewrite_stake::id(),
|
&Feature { activated_at: None },
|
||||||
&feature::create_account(
|
feature_account_balance,
|
||||||
&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;
|
let mut store_failed_count = 0;
|
||||||
if base_bank
|
if force_enabled_count >= 1 {
|
||||||
.get_account(&feature_set::secp256k1_program_enabled::id())
|
if base_bank
|
||||||
.is_some()
|
.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!
|
// steal some lamports from the pretty old feature not to affect
|
||||||
base_bank.store_account(
|
// capitalizaion, which doesn't affect inflation behavior!
|
||||||
&feature_set::secp256k1_program_enabled::id(),
|
base_bank.store_account(
|
||||||
&Account::default(),
|
&feature_set::secp256k1_program_enabled::id(),
|
||||||
);
|
&Account::default(),
|
||||||
} else {
|
);
|
||||||
store_failed_count += 1;
|
force_enabled_count -= 1;
|
||||||
|
} else {
|
||||||
|
store_failed_count += 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if base_bank
|
if force_enabled_count >= 1 {
|
||||||
.get_account(&feature_set::instructions_sysvar_enabled::id())
|
if base_bank
|
||||||
.is_some()
|
.get_account(&feature_set::instructions_sysvar_enabled::id())
|
||||||
{
|
.is_some()
|
||||||
base_bank.store_account(
|
{
|
||||||
&feature_set::instructions_sysvar_enabled::id(),
|
// steal some lamports from the pretty old feature not to affect
|
||||||
&Account::default(),
|
// capitalizaion, which doesn't affect inflation behavior!
|
||||||
);
|
base_bank.store_account(
|
||||||
} else {
|
&feature_set::instructions_sysvar_enabled::id(),
|
||||||
store_failed_count += 1;
|
&Account::default(),
|
||||||
|
);
|
||||||
|
force_enabled_count -= 1;
|
||||||
|
} else {
|
||||||
|
store_failed_count += 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
assert_eq!(force_enabled_count, store_failed_count);
|
||||||
if store_failed_count >= 1 {
|
if store_failed_count >= 1 {
|
||||||
// we have no choice; maybe locally created blank cluster with
|
// we have no choice; maybe locally created blank cluster with
|
||||||
// not-Development cluster type.
|
// 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)]
|
#[derive(Default, Debug)]
|
||||||
struct CalculationDetail {
|
struct CalculationDetail {
|
||||||
epochs: usize,
|
epochs: usize,
|
||||||
voter: Pubkey,
|
voter: Pubkey,
|
||||||
voter_owner: Pubkey,
|
voter_owner: Pubkey,
|
||||||
point: u128,
|
current_effective_stake: u64,
|
||||||
stake: u128,
|
|
||||||
total_stake: u64,
|
total_stake: u64,
|
||||||
rent_exempt_reserve: u64,
|
rent_exempt_reserve: u64,
|
||||||
credits: u128,
|
points: Vec<PointDetail>,
|
||||||
base_rewards: u64,
|
base_rewards: u64,
|
||||||
commission: u8,
|
commission: u8,
|
||||||
vote_rewards: u64,
|
vote_rewards: u64,
|
||||||
@ -2120,7 +2147,8 @@ fn main() {
|
|||||||
activation_epoch: Epoch,
|
activation_epoch: Epoch,
|
||||||
deactivation_epoch: Option<Epoch>,
|
deactivation_epoch: Option<Epoch>,
|
||||||
point_value: Option<PointValue>,
|
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;
|
use solana_stake_program::stake_state::InflationPointCalculationEvent;
|
||||||
let mut stake_calcuration_details: HashMap<Pubkey, CalculationDetail> =
|
let mut stake_calcuration_details: HashMap<Pubkey, CalculationDetail> =
|
||||||
@ -2134,16 +2162,14 @@ fn main() {
|
|||||||
let detail = stake_calcuration_details.entry(**pubkey).or_default();
|
let detail = stake_calcuration_details.entry(**pubkey).or_default();
|
||||||
match event {
|
match event {
|
||||||
InflationPointCalculationEvent::CalculatedPoints(
|
InflationPointCalculationEvent::CalculatedPoints(
|
||||||
point,
|
epoch,
|
||||||
stake,
|
stake,
|
||||||
credits,
|
credits,
|
||||||
|
points,
|
||||||
) => {
|
) => {
|
||||||
// Don't sum for epochs where no credits are earned
|
if *points > 0 {
|
||||||
if *credits > 0 {
|
|
||||||
detail.epochs += 1;
|
detail.epochs += 1;
|
||||||
detail.point += *point;
|
detail.points.push(PointDetail {epoch: *epoch, points: *points, stake: *stake, credits: *credits});
|
||||||
detail.stake += *stake;
|
|
||||||
detail.credits += *credits;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
InflationPointCalculationEvent::SplitRewards(
|
InflationPointCalculationEvent::SplitRewards(
|
||||||
@ -2166,6 +2192,9 @@ fn main() {
|
|||||||
last_point_value = point_value;
|
last_point_value = point_value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
InflationPointCalculationEvent::EffectiveStakeAtRewardedEpoch(stake) => {
|
||||||
|
detail.current_effective_stake = *stake;
|
||||||
|
}
|
||||||
InflationPointCalculationEvent::Commission(commission) => {
|
InflationPointCalculationEvent::Commission(commission) => {
|
||||||
detail.commission = *commission;
|
detail.commission = *commission;
|
||||||
}
|
}
|
||||||
@ -2173,9 +2202,11 @@ fn main() {
|
|||||||
detail.rent_exempt_reserve = *reserve;
|
detail.rent_exempt_reserve = *reserve;
|
||||||
}
|
}
|
||||||
InflationPointCalculationEvent::CreditsObserved(
|
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(
|
InflationPointCalculationEvent::Delegation(
|
||||||
delegation,
|
delegation,
|
||||||
@ -2316,8 +2347,12 @@ fn main() {
|
|||||||
activation_epoch: String,
|
activation_epoch: String,
|
||||||
deactivation_epoch: String,
|
deactivation_epoch: String,
|
||||||
earned_epochs: String,
|
earned_epochs: String,
|
||||||
earned_credits: String,
|
epoch: String,
|
||||||
credits_observed: String,
|
epoch_credits: String,
|
||||||
|
epoch_points: String,
|
||||||
|
epoch_stake: String,
|
||||||
|
old_credits_observed: String,
|
||||||
|
new_credits_observed: String,
|
||||||
base_rewards: String,
|
base_rewards: String,
|
||||||
stake_rewards: String,
|
stake_rewards: String,
|
||||||
vote_rewards: String,
|
vote_rewards: String,
|
||||||
@ -2331,53 +2366,82 @@ fn main() {
|
|||||||
data.map(|data| format!("{}", data))
|
data.map(|data| format!("{}", data))
|
||||||
.unwrap_or_else(|| "N/A".to_owned())
|
.unwrap_or_else(|| "N/A".to_owned())
|
||||||
};
|
};
|
||||||
let record = InflationRecord {
|
let mut point_details = detail
|
||||||
account: format!("{}", pubkey),
|
.map(|d| d.points.iter().map(Some).collect::<Vec<_>>())
|
||||||
owner: format!("{}", base_account.owner),
|
.unwrap_or_default();
|
||||||
old_balance: base_account.lamports,
|
|
||||||
new_balance: warped_account.lamports,
|
// ensure to print even if there is no calculation/point detail
|
||||||
data_size: base_account.data.len(),
|
if point_details.is_empty() {
|
||||||
delegation: format_or_na(detail.map(|d| d.voter)),
|
point_details.push(None);
|
||||||
delegation_owner: format_or_na(
|
}
|
||||||
detail.map(|d| d.voter_owner),
|
|
||||||
),
|
for point_detail in point_details {
|
||||||
effective_stake: format_or_na(detail.map(|d| d.stake)),
|
let record = InflationRecord {
|
||||||
delegated_stake: format_or_na(
|
account: format!("{}", pubkey),
|
||||||
detail.map(|d| d.total_stake),
|
owner: format!("{}", base_account.owner),
|
||||||
),
|
old_balance: base_account.lamports,
|
||||||
rent_exempt_reserve: format_or_na(
|
new_balance: warped_account.lamports,
|
||||||
detail.map(|d| d.rent_exempt_reserve),
|
data_size: base_account.data.len(),
|
||||||
),
|
delegation: format_or_na(detail.map(|d| d.voter)),
|
||||||
activation_epoch: format_or_na(detail.map(|d| {
|
delegation_owner: format_or_na(
|
||||||
if d.activation_epoch < Epoch::max_value() {
|
detail.map(|d| d.voter_owner),
|
||||||
d.activation_epoch
|
),
|
||||||
} else {
|
effective_stake: format_or_na(
|
||||||
// bootstraped
|
detail.map(|d| d.current_effective_stake),
|
||||||
0
|
),
|
||||||
}
|
delegated_stake: format_or_na(
|
||||||
})),
|
detail.map(|d| d.total_stake),
|
||||||
deactivation_epoch: format_or_na(
|
),
|
||||||
detail.and_then(|d| d.deactivation_epoch),
|
rent_exempt_reserve: format_or_na(
|
||||||
),
|
detail.map(|d| d.rent_exempt_reserve),
|
||||||
earned_epochs: format_or_na(detail.map(|d| d.epochs)),
|
),
|
||||||
earned_credits: format_or_na(detail.map(|d| d.credits)),
|
activation_epoch: format_or_na(detail.map(|d| {
|
||||||
credits_observed: format_or_na(
|
if d.activation_epoch < Epoch::max_value() {
|
||||||
detail.and_then(|d| d.credits_observed),
|
d.activation_epoch
|
||||||
),
|
} else {
|
||||||
base_rewards: format_or_na(detail.map(|d| d.base_rewards)),
|
// bootstraped
|
||||||
stake_rewards: format_or_na(
|
0
|
||||||
detail.map(|d| d.stake_rewards),
|
}
|
||||||
),
|
})),
|
||||||
vote_rewards: format_or_na(detail.map(|d| d.vote_rewards)),
|
deactivation_epoch: format_or_na(
|
||||||
commission: format_or_na(detail.map(|d| d.commission)),
|
detail.and_then(|d| d.deactivation_epoch),
|
||||||
cluster_rewards: format_or_na(
|
),
|
||||||
last_point_value.as_ref().map(|pv| pv.rewards),
|
earned_epochs: format_or_na(detail.map(|d| d.epochs)),
|
||||||
),
|
epoch: format_or_na(point_detail.map(|d| d.epoch)),
|
||||||
cluster_points: format_or_na(
|
epoch_credits: format_or_na(
|
||||||
last_point_value.as_ref().map(|pv| pv.points),
|
point_detail.map(|d| d.credits),
|
||||||
),
|
),
|
||||||
};
|
epoch_points: format_or_na(
|
||||||
csv_writer.serialize(&record).unwrap();
|
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;
|
overall_delta += delta;
|
||||||
} else {
|
} else {
|
||||||
|
@ -33,12 +33,13 @@ pub enum StakeState {
|
|||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum InflationPointCalculationEvent {
|
pub enum InflationPointCalculationEvent {
|
||||||
CalculatedPoints(u128, u128, u128),
|
CalculatedPoints(u64, u128, u128, u128),
|
||||||
SplitRewards(u64, u64, u64, PointValue),
|
SplitRewards(u64, u64, u64, PointValue),
|
||||||
|
EffectiveStakeAtRewardedEpoch(u64),
|
||||||
RentExemptReserve(u64),
|
RentExemptReserve(u64),
|
||||||
Delegation(Delegation, Pubkey),
|
Delegation(Delegation, Pubkey),
|
||||||
Commission(u8),
|
Commission(u8),
|
||||||
CreditsObserved(u64),
|
CreditsObserved(u64, u64),
|
||||||
}
|
}
|
||||||
|
|
||||||
fn null_tracer() -> Option<impl FnMut(&InflationPointCalculationEvent)> {
|
fn null_tracer() -> Option<impl FnMut(&InflationPointCalculationEvent)> {
|
||||||
@ -521,12 +522,13 @@ impl Stake {
|
|||||||
fix_stake_deactivate,
|
fix_stake_deactivate,
|
||||||
)
|
)
|
||||||
.map(|(stakers_reward, voters_reward, credits_observed)| {
|
.map(|(stakers_reward, voters_reward, credits_observed)| {
|
||||||
self.credits_observed = credits_observed;
|
|
||||||
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(
|
||||||
|
self.credits_observed,
|
||||||
credits_observed,
|
credits_observed,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
self.credits_observed = credits_observed;
|
||||||
self.delegation.stake += stakers_reward;
|
self.delegation.stake += stakers_reward;
|
||||||
(stakers_reward, voters_reward)
|
(stakers_reward, voters_reward)
|
||||||
})
|
})
|
||||||
@ -594,13 +596,15 @@ impl Stake {
|
|||||||
new_credits_observed = new_credits_observed.max(final_epoch_credits);
|
new_credits_observed = new_credits_observed.max(final_epoch_credits);
|
||||||
|
|
||||||
// finally calculate points for this epoch
|
// 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 {
|
if let Some(inflation_point_calc_tracer) = inflation_point_calc_tracer {
|
||||||
inflation_point_calc_tracer(&InflationPointCalculationEvent::CalculatedPoints(
|
inflation_point_calc_tracer(&InflationPointCalculationEvent::CalculatedPoints(
|
||||||
points,
|
epoch,
|
||||||
stake,
|
stake,
|
||||||
earned_credits,
|
earned_credits,
|
||||||
|
earned_points,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1298,6 +1302,7 @@ impl MergeKind {
|
|||||||
// utility function, used by runtime
|
// utility function, used by runtime
|
||||||
// returns a tuple of (stakers_reward,voters_reward)
|
// returns a tuple of (stakers_reward,voters_reward)
|
||||||
pub fn redeem_rewards(
|
pub fn redeem_rewards(
|
||||||
|
rewarded_epoch: Epoch,
|
||||||
stake_account: &mut Account,
|
stake_account: &mut Account,
|
||||||
vote_account: &mut Account,
|
vote_account: &mut Account,
|
||||||
point_value: &PointValue,
|
point_value: &PointValue,
|
||||||
@ -1309,6 +1314,13 @@ pub fn redeem_rewards(
|
|||||||
let vote_state: VoteState =
|
let vote_state: VoteState =
|
||||||
StateMut::<VoteStateVersions>::state(vote_account)?.convert_to_current();
|
StateMut::<VoteStateVersions>::state(vote_account)?.convert_to_current();
|
||||||
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::EffectiveStakeAtRewardedEpoch(stake.stake(
|
||||||
|
rewarded_epoch,
|
||||||
|
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,
|
||||||
));
|
));
|
||||||
|
@ -1458,6 +1458,7 @@ 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 = self.pay_validator_rewards(
|
||||||
|
prev_epoch,
|
||||||
validator_rewards,
|
validator_rewards,
|
||||||
reward_calc_tracer,
|
reward_calc_tracer,
|
||||||
self.stake_program_v2_enabled(),
|
self.stake_program_v2_enabled(),
|
||||||
@ -1576,6 +1577,7 @@ impl Bank {
|
|||||||
/// successfully load and parse, return the lamport value of one point
|
/// successfully load and parse, return the lamport value of one point
|
||||||
fn pay_validator_rewards(
|
fn pay_validator_rewards(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
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,
|
fix_stake_deactivate: bool,
|
||||||
@ -1624,6 +1626,7 @@ impl Bank {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
let redeemed = stake_state::redeem_rewards(
|
let redeemed = stake_state::redeem_rewards(
|
||||||
|
rewarded_epoch,
|
||||||
stake_account,
|
stake_account,
|
||||||
vote_account,
|
vote_account,
|
||||||
&point_value,
|
&point_value,
|
||||||
|
Reference in New Issue
Block a user