Expose all rewards (fees, rent, voting and staking) in RPC getConfirmedBlock and the cli
This commit is contained in:
parent
403790760c
commit
c5c8da1ac0
|
@ -4659,6 +4659,7 @@ dependencies = [
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"solana-account-decoder",
|
"solana-account-decoder",
|
||||||
|
"solana-runtime",
|
||||||
"solana-sdk 1.5.0",
|
"solana-sdk 1.5.0",
|
||||||
"solana-stake-program",
|
"solana-stake-program",
|
||||||
"solana-vote-program",
|
"solana-vote-program",
|
||||||
|
|
|
@ -98,7 +98,7 @@ pub enum CliCommand {
|
||||||
Fees,
|
Fees,
|
||||||
FirstAvailableBlock,
|
FirstAvailableBlock,
|
||||||
GetBlock {
|
GetBlock {
|
||||||
slot: Slot,
|
slot: Option<Slot>,
|
||||||
},
|
},
|
||||||
GetBlockTime {
|
GetBlockTime {
|
||||||
slot: Option<Slot>,
|
slot: Option<Slot>,
|
||||||
|
|
|
@ -73,8 +73,7 @@ impl ClusterQuerySubCommands for App<'_, '_> {
|
||||||
.validator(is_slot)
|
.validator(is_slot)
|
||||||
.value_name("SLOT")
|
.value_name("SLOT")
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
.index(1)
|
.index(1),
|
||||||
.required(true),
|
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.subcommand(
|
.subcommand(
|
||||||
|
@ -363,7 +362,7 @@ pub fn parse_cluster_ping(
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_get_block(matches: &ArgMatches<'_>) -> Result<CliCommandInfo, CliError> {
|
pub fn parse_get_block(matches: &ArgMatches<'_>) -> Result<CliCommandInfo, CliError> {
|
||||||
let slot = value_t_or_exit!(matches, "slot", Slot);
|
let slot = value_of(matches, "slot");
|
||||||
Ok(CliCommandInfo {
|
Ok(CliCommandInfo {
|
||||||
command: CliCommand::GetBlock { slot },
|
command: CliCommand::GetBlock { slot },
|
||||||
signers: vec![],
|
signers: vec![],
|
||||||
|
@ -700,7 +699,17 @@ pub fn process_leader_schedule(rpc_client: &RpcClient) -> ProcessResult {
|
||||||
Ok("".to_string())
|
Ok("".to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn process_get_block(rpc_client: &RpcClient, _config: &CliConfig, slot: Slot) -> ProcessResult {
|
pub fn process_get_block(
|
||||||
|
rpc_client: &RpcClient,
|
||||||
|
_config: &CliConfig,
|
||||||
|
slot: Option<Slot>,
|
||||||
|
) -> ProcessResult {
|
||||||
|
let slot = if let Some(slot) = slot {
|
||||||
|
slot
|
||||||
|
} else {
|
||||||
|
rpc_client.get_slot()?
|
||||||
|
};
|
||||||
|
|
||||||
let mut block =
|
let mut block =
|
||||||
rpc_client.get_confirmed_block_with_encoding(slot, UiTransactionEncoding::Base64)?;
|
rpc_client.get_confirmed_block_with_encoding(slot, UiTransactionEncoding::Base64)?;
|
||||||
|
|
||||||
|
@ -716,18 +725,23 @@ pub fn process_get_block(rpc_client: &RpcClient, _config: &CliConfig, slot: Slot
|
||||||
let mut total_rewards = 0;
|
let mut total_rewards = 0;
|
||||||
println!("Rewards:",);
|
println!("Rewards:",);
|
||||||
println!(
|
println!(
|
||||||
" {:<44} {:<15} {:<13} {:>14}",
|
" {:<44} {:^15} {:<15} {:<20} {:>14}",
|
||||||
"Address", "Amount", "New Balance", "Percent Change"
|
"Address", "Type", "Amount", "New Balance", "Percent Change"
|
||||||
);
|
);
|
||||||
for reward in block.rewards {
|
for reward in block.rewards {
|
||||||
let sign = if reward.lamports < 0 { "-" } else { "" };
|
let sign = if reward.lamports < 0 { "-" } else { "" };
|
||||||
|
|
||||||
total_rewards += reward.lamports;
|
total_rewards += reward.lamports;
|
||||||
println!(
|
println!(
|
||||||
" {:<44} {:>15} {}",
|
" {:<44} {:^15} {:>15} {}",
|
||||||
reward.pubkey,
|
reward.pubkey,
|
||||||
|
if let Some(reward_type) = reward.reward_type {
|
||||||
|
format!("{}", reward_type)
|
||||||
|
} else {
|
||||||
|
"-".to_string()
|
||||||
|
},
|
||||||
format!(
|
format!(
|
||||||
"{}◎{:<14.4}",
|
"{}◎{:<14.9}",
|
||||||
sign,
|
sign,
|
||||||
lamports_to_sol(reward.lamports.abs() as u64)
|
lamports_to_sol(reward.lamports.abs() as u64)
|
||||||
),
|
),
|
||||||
|
@ -735,7 +749,7 @@ pub fn process_get_block(rpc_client: &RpcClient, _config: &CliConfig, slot: Slot
|
||||||
" - -".to_string()
|
" - -".to_string()
|
||||||
} else {
|
} else {
|
||||||
format!(
|
format!(
|
||||||
"◎{:<12.4} {:>13.9}%",
|
"◎{:<19.9} {:>13.9}%",
|
||||||
lamports_to_sol(reward.post_balance),
|
lamports_to_sol(reward.post_balance),
|
||||||
reward.lamports.abs() as f64
|
reward.lamports.abs() as f64
|
||||||
/ (reward.post_balance as f64 - reward.lamports as f64)
|
/ (reward.post_balance as f64 - reward.lamports as f64)
|
||||||
|
@ -746,7 +760,7 @@ pub fn process_get_block(rpc_client: &RpcClient, _config: &CliConfig, slot: Slot
|
||||||
|
|
||||||
let sign = if total_rewards < 0 { "-" } else { "" };
|
let sign = if total_rewards < 0 { "-" } else { "" };
|
||||||
println!(
|
println!(
|
||||||
"Total Rewards: {}◎{:12.9}",
|
"Total Rewards: {}◎{:<12.9}",
|
||||||
sign,
|
sign,
|
||||||
lamports_to_sol(total_rewards.abs() as u64)
|
lamports_to_sol(total_rewards.abs() as u64)
|
||||||
);
|
);
|
||||||
|
|
|
@ -291,7 +291,6 @@ impl ReplayStage {
|
||||||
&bank_forks,
|
&bank_forks,
|
||||||
&leader_schedule_cache,
|
&leader_schedule_cache,
|
||||||
&subscriptions,
|
&subscriptions,
|
||||||
rewards_recorder_sender.clone(),
|
|
||||||
&mut progress,
|
&mut progress,
|
||||||
&mut all_pubkeys,
|
&mut all_pubkeys,
|
||||||
);
|
);
|
||||||
|
@ -313,6 +312,7 @@ impl ReplayStage {
|
||||||
&mut heaviest_subtree_fork_choice,
|
&mut heaviest_subtree_fork_choice,
|
||||||
&replay_vote_sender,
|
&replay_vote_sender,
|
||||||
&bank_notification_sender,
|
&bank_notification_sender,
|
||||||
|
&rewards_recorder_sender,
|
||||||
);
|
);
|
||||||
replay_active_banks_time.stop();
|
replay_active_banks_time.stop();
|
||||||
Self::report_memory(&allocated, "replay_active_banks", start);
|
Self::report_memory(&allocated, "replay_active_banks", start);
|
||||||
|
@ -554,7 +554,6 @@ impl ReplayStage {
|
||||||
&poh_recorder,
|
&poh_recorder,
|
||||||
&leader_schedule_cache,
|
&leader_schedule_cache,
|
||||||
&subscriptions,
|
&subscriptions,
|
||||||
rewards_recorder_sender.clone(),
|
|
||||||
&progress,
|
&progress,
|
||||||
&retransmit_slots_sender,
|
&retransmit_slots_sender,
|
||||||
&mut skipped_slots_info,
|
&mut skipped_slots_info,
|
||||||
|
@ -854,7 +853,6 @@ impl ReplayStage {
|
||||||
poh_recorder: &Arc<Mutex<PohRecorder>>,
|
poh_recorder: &Arc<Mutex<PohRecorder>>,
|
||||||
leader_schedule_cache: &Arc<LeaderScheduleCache>,
|
leader_schedule_cache: &Arc<LeaderScheduleCache>,
|
||||||
subscriptions: &Arc<RpcSubscriptions>,
|
subscriptions: &Arc<RpcSubscriptions>,
|
||||||
rewards_recorder_sender: Option<RewardsRecorderSender>,
|
|
||||||
progress_map: &ProgressMap,
|
progress_map: &ProgressMap,
|
||||||
retransmit_slots_sender: &RetransmitSlotsSender,
|
retransmit_slots_sender: &RetransmitSlotsSender,
|
||||||
skipped_slots_info: &mut SkippedSlotsInfo,
|
skipped_slots_info: &mut SkippedSlotsInfo,
|
||||||
|
@ -953,7 +951,6 @@ impl ReplayStage {
|
||||||
poh_slot,
|
poh_slot,
|
||||||
root_slot,
|
root_slot,
|
||||||
my_pubkey,
|
my_pubkey,
|
||||||
&rewards_recorder_sender,
|
|
||||||
subscriptions,
|
subscriptions,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1265,6 +1262,7 @@ impl ReplayStage {
|
||||||
heaviest_subtree_fork_choice: &mut HeaviestSubtreeForkChoice,
|
heaviest_subtree_fork_choice: &mut HeaviestSubtreeForkChoice,
|
||||||
replay_vote_sender: &ReplayVoteSender,
|
replay_vote_sender: &ReplayVoteSender,
|
||||||
bank_notification_sender: &Option<BankNotificationSender>,
|
bank_notification_sender: &Option<BankNotificationSender>,
|
||||||
|
rewards_recorder_sender: &Option<RewardsRecorderSender>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
let mut did_complete_bank = false;
|
let mut did_complete_bank = false;
|
||||||
let mut tx_count = 0;
|
let mut tx_count = 0;
|
||||||
|
@ -1340,6 +1338,8 @@ impl ReplayStage {
|
||||||
.send(BankNotification::Frozen(bank.clone()))
|
.send(BankNotification::Frozen(bank.clone()))
|
||||||
.unwrap_or_else(|err| warn!("bank_notification_sender failed: {:?}", err));
|
.unwrap_or_else(|err| warn!("bank_notification_sender failed: {:?}", err));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Self::record_rewards(&bank, &rewards_recorder_sender);
|
||||||
} else {
|
} else {
|
||||||
trace!(
|
trace!(
|
||||||
"bank {} not completed tick_height: {}, max_tick_height: {}",
|
"bank {} not completed tick_height: {}, max_tick_height: {}",
|
||||||
|
@ -1817,7 +1817,6 @@ impl ReplayStage {
|
||||||
bank_forks: &RwLock<BankForks>,
|
bank_forks: &RwLock<BankForks>,
|
||||||
leader_schedule_cache: &Arc<LeaderScheduleCache>,
|
leader_schedule_cache: &Arc<LeaderScheduleCache>,
|
||||||
subscriptions: &Arc<RpcSubscriptions>,
|
subscriptions: &Arc<RpcSubscriptions>,
|
||||||
rewards_recorder_sender: Option<RewardsRecorderSender>,
|
|
||||||
progress: &mut ProgressMap,
|
progress: &mut ProgressMap,
|
||||||
all_pubkeys: &mut PubkeyReferences,
|
all_pubkeys: &mut PubkeyReferences,
|
||||||
) {
|
) {
|
||||||
|
@ -1863,7 +1862,6 @@ impl ReplayStage {
|
||||||
child_slot,
|
child_slot,
|
||||||
forks.root(),
|
forks.root(),
|
||||||
&leader,
|
&leader,
|
||||||
&rewards_recorder_sender,
|
|
||||||
subscriptions,
|
subscriptions,
|
||||||
);
|
);
|
||||||
let empty: Vec<&Pubkey> = vec![];
|
let empty: Vec<&Pubkey> = vec![];
|
||||||
|
@ -1891,21 +1889,18 @@ impl ReplayStage {
|
||||||
slot: u64,
|
slot: u64,
|
||||||
root_slot: u64,
|
root_slot: u64,
|
||||||
leader: &Pubkey,
|
leader: &Pubkey,
|
||||||
rewards_recorder_sender: &Option<RewardsRecorderSender>,
|
|
||||||
subscriptions: &Arc<RpcSubscriptions>,
|
subscriptions: &Arc<RpcSubscriptions>,
|
||||||
) -> Bank {
|
) -> Bank {
|
||||||
subscriptions.notify_slot(slot, parent.slot(), root_slot);
|
subscriptions.notify_slot(slot, parent.slot(), root_slot);
|
||||||
|
Bank::new_from_parent(parent, leader, slot)
|
||||||
let child_bank = Bank::new_from_parent(parent, leader, slot);
|
|
||||||
Self::record_rewards(&child_bank, &rewards_recorder_sender);
|
|
||||||
child_bank
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn record_rewards(bank: &Bank, rewards_recorder_sender: &Option<RewardsRecorderSender>) {
|
fn record_rewards(bank: &Bank, rewards_recorder_sender: &Option<RewardsRecorderSender>) {
|
||||||
if let Some(rewards_recorder_sender) = rewards_recorder_sender {
|
if let Some(rewards_recorder_sender) = rewards_recorder_sender {
|
||||||
if let Some(ref rewards) = bank.rewards {
|
let rewards = bank.rewards.read().unwrap();
|
||||||
|
if !rewards.is_empty() {
|
||||||
rewards_recorder_sender
|
rewards_recorder_sender
|
||||||
.send((bank.slot(), rewards.iter().copied().collect()))
|
.send((bank.slot(), rewards.clone()))
|
||||||
.unwrap_or_else(|err| warn!("rewards_recorder_sender failed: {:?}", err));
|
.unwrap_or_else(|err| warn!("rewards_recorder_sender failed: {:?}", err));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2155,7 +2150,6 @@ pub(crate) mod tests {
|
||||||
&bank_forks,
|
&bank_forks,
|
||||||
&leader_schedule_cache,
|
&leader_schedule_cache,
|
||||||
&rpc_subscriptions,
|
&rpc_subscriptions,
|
||||||
None,
|
|
||||||
&mut progress,
|
&mut progress,
|
||||||
&mut PubkeyReferences::default(),
|
&mut PubkeyReferences::default(),
|
||||||
);
|
);
|
||||||
|
@ -2179,7 +2173,6 @@ pub(crate) mod tests {
|
||||||
&bank_forks,
|
&bank_forks,
|
||||||
&leader_schedule_cache,
|
&leader_schedule_cache,
|
||||||
&rpc_subscriptions,
|
&rpc_subscriptions,
|
||||||
None,
|
|
||||||
&mut progress,
|
&mut progress,
|
||||||
&mut PubkeyReferences::default(),
|
&mut PubkeyReferences::default(),
|
||||||
);
|
);
|
||||||
|
|
|
@ -54,6 +54,7 @@ impl RewardsRecorderService {
|
||||||
pubkey: pubkey.to_string(),
|
pubkey: pubkey.to_string(),
|
||||||
lamports: reward_info.lamports,
|
lamports: reward_info.lamports,
|
||||||
post_balance: reward_info.post_balance,
|
post_balance: reward_info.post_balance,
|
||||||
|
reward_type: Some(reward_info.reward_type),
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
|
|
|
@ -342,6 +342,7 @@ The result field will be an object with the following fields:
|
||||||
- `pubkey: <string>` - The public key, as base-58 encoded string, of the account that received the reward
|
- `pubkey: <string>` - The public key, as base-58 encoded string, of the account that received the reward
|
||||||
- `lamports: <i64>`- number of reward lamports credited or debited by the account, as a i64
|
- `lamports: <i64>`- number of reward lamports credited or debited by the account, as a i64
|
||||||
- `postBalance: <u64>` - account balance in lamports after the reward was applied
|
- `postBalance: <u64>` - account balance in lamports after the reward was applied
|
||||||
|
- `rewardType: <string|undefined>` - type of reward: "fee", "rent", "voting", "staking"
|
||||||
- `blockTime: <i64 | null>` - estimated production time, as Unix timestamp (seconds since the Unix epoch). null if not available
|
- `blockTime: <i64 | null>` - estimated production time, as Unix timestamp (seconds since the Unix epoch). null if not available
|
||||||
|
|
||||||
#### Example:
|
#### Example:
|
||||||
|
|
|
@ -69,7 +69,7 @@ use std::{
|
||||||
cell::RefCell,
|
cell::RefCell,
|
||||||
collections::{HashMap, HashSet},
|
collections::{HashMap, HashSet},
|
||||||
convert::{TryFrom, TryInto},
|
convert::{TryFrom, TryInto},
|
||||||
mem,
|
fmt, mem,
|
||||||
ops::RangeInclusive,
|
ops::RangeInclusive,
|
||||||
path::PathBuf,
|
path::PathBuf,
|
||||||
ptr,
|
ptr,
|
||||||
|
@ -525,8 +525,32 @@ impl PartialEq for Bank {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Serialize, Deserialize, AbiExample, Default, Clone, Copy)]
|
#[derive(Debug, PartialEq, Serialize, Deserialize, AbiExample, AbiEnumVisitor, Clone, Copy)]
|
||||||
|
pub enum RewardType {
|
||||||
|
Fee,
|
||||||
|
Rent,
|
||||||
|
Staking,
|
||||||
|
Voting,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for RewardType {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"{}",
|
||||||
|
match self {
|
||||||
|
RewardType::Fee => "fee",
|
||||||
|
RewardType::Rent => "rent",
|
||||||
|
RewardType::Staking => "staking",
|
||||||
|
RewardType::Voting => "voting",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Serialize, Deserialize, AbiExample, Clone, Copy)]
|
||||||
pub struct RewardInfo {
|
pub struct RewardInfo {
|
||||||
|
pub reward_type: RewardType,
|
||||||
pub lamports: i64, // Reward amount
|
pub lamports: i64, // Reward amount
|
||||||
pub post_balance: u64, // Account balance in lamports after `lamports` was applied
|
pub post_balance: u64, // Account balance in lamports after `lamports` was applied
|
||||||
}
|
}
|
||||||
|
@ -613,7 +637,7 @@ pub struct Bank {
|
||||||
/// Track cluster signature throughput and adjust fee rate
|
/// Track cluster signature throughput and adjust fee rate
|
||||||
fee_rate_governor: FeeRateGovernor,
|
fee_rate_governor: FeeRateGovernor,
|
||||||
|
|
||||||
/// Rent that have been collected
|
/// Rent that has been collected
|
||||||
collected_rent: AtomicU64,
|
collected_rent: AtomicU64,
|
||||||
|
|
||||||
/// latest rent collector, knows the epoch
|
/// latest rent collector, knows the epoch
|
||||||
|
@ -645,8 +669,8 @@ pub struct Bank {
|
||||||
/// Last time when the cluster info vote listener has synced with this bank
|
/// Last time when the cluster info vote listener has synced with this bank
|
||||||
pub last_vote_sync: AtomicU64,
|
pub last_vote_sync: AtomicU64,
|
||||||
|
|
||||||
/// Rewards that were paid out immediately after this bank was created
|
/// Protocol-level rewards that were distributed by this bank
|
||||||
pub rewards: Option<Vec<(Pubkey, RewardInfo)>>,
|
pub rewards: RwLock<Vec<(Pubkey, RewardInfo)>>,
|
||||||
|
|
||||||
pub skip_drop: AtomicBool,
|
pub skip_drop: AtomicBool,
|
||||||
|
|
||||||
|
@ -780,7 +804,7 @@ impl Bank {
|
||||||
feature_builtins: parent.feature_builtins.clone(),
|
feature_builtins: parent.feature_builtins.clone(),
|
||||||
hard_forks: parent.hard_forks.clone(),
|
hard_forks: parent.hard_forks.clone(),
|
||||||
last_vote_sync: AtomicU64::new(parent.last_vote_sync.load(Relaxed)),
|
last_vote_sync: AtomicU64::new(parent.last_vote_sync.load(Relaxed)),
|
||||||
rewards: None,
|
rewards: RwLock::new(vec![]),
|
||||||
skip_drop: AtomicBool::new(false),
|
skip_drop: AtomicBool::new(false),
|
||||||
cluster_type: parent.cluster_type,
|
cluster_type: parent.cluster_type,
|
||||||
lazy_rent_collection: AtomicBool::new(parent.lazy_rent_collection.load(Relaxed)),
|
lazy_rent_collection: AtomicBool::new(parent.lazy_rent_collection.load(Relaxed)),
|
||||||
|
@ -1168,7 +1192,7 @@ impl Bank {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// update reward for previous epoch
|
// update rewards based on the previous epoch
|
||||||
fn update_rewards(&mut self, prev_epoch: Epoch) {
|
fn update_rewards(&mut self, prev_epoch: Epoch) {
|
||||||
if prev_epoch == self.epoch() {
|
if prev_epoch == self.epoch() {
|
||||||
return;
|
return;
|
||||||
|
@ -1216,18 +1240,23 @@ impl Bank {
|
||||||
|
|
||||||
let validator_rewards_paid =
|
let validator_rewards_paid =
|
||||||
self.stakes.read().unwrap().vote_balance_and_staked() - vote_balance_and_staked;
|
self.stakes.read().unwrap().vote_balance_and_staked() - vote_balance_and_staked;
|
||||||
if let Some(rewards) = self.rewards.as_ref() {
|
assert_eq!(
|
||||||
assert_eq!(
|
validator_rewards_paid,
|
||||||
validator_rewards_paid,
|
u64::try_from(
|
||||||
u64::try_from(
|
self.rewards
|
||||||
rewards
|
.read()
|
||||||
.iter()
|
.unwrap()
|
||||||
.map(|(_pubkey, reward_info)| reward_info.lamports)
|
.iter()
|
||||||
.sum::<i64>()
|
.map(|(_address, reward_info)| {
|
||||||
)
|
match reward_info.reward_type {
|
||||||
.unwrap()
|
RewardType::Voting | RewardType::Staking => reward_info.lamports,
|
||||||
);
|
_ => 0,
|
||||||
}
|
}
|
||||||
|
})
|
||||||
|
.sum::<i64>()
|
||||||
|
)
|
||||||
|
.unwrap()
|
||||||
|
);
|
||||||
|
|
||||||
// verify that we didn't pay any more than we expected to
|
// verify that we didn't pay any more than we expected to
|
||||||
assert!(validator_rewards >= validator_rewards_paid);
|
assert!(validator_rewards >= validator_rewards_paid);
|
||||||
|
@ -1318,11 +1347,12 @@ impl Bank {
|
||||||
|
|
||||||
let point_value = PointValue { rewards, points };
|
let point_value = PointValue { rewards, points };
|
||||||
|
|
||||||
let mut rewards = HashMap::new();
|
let mut rewards = vec![];
|
||||||
|
|
||||||
// pay according to point value
|
// pay according to point value
|
||||||
for (vote_pubkey, (stake_group, vote_account)) in stake_delegation_accounts.iter_mut() {
|
for (vote_pubkey, (stake_group, vote_account)) in stake_delegation_accounts.iter_mut() {
|
||||||
let mut vote_account_changed = false;
|
let mut vote_account_changed = false;
|
||||||
|
let voters_account_pre_balance = vote_account.lamports;
|
||||||
|
|
||||||
for (stake_pubkey, stake_account) in stake_group.iter_mut() {
|
for (stake_pubkey, stake_account) in stake_group.iter_mut() {
|
||||||
let redeemed = stake_state::redeem_rewards(
|
let redeemed = stake_state::redeem_rewards(
|
||||||
stake_account,
|
stake_account,
|
||||||
|
@ -1330,24 +1360,19 @@ impl Bank {
|
||||||
&point_value,
|
&point_value,
|
||||||
Some(&stake_history),
|
Some(&stake_history),
|
||||||
);
|
);
|
||||||
if let Ok((stakers_reward, voters_reward)) = redeemed {
|
if let Ok((stakers_reward, _voters_reward)) = redeemed {
|
||||||
self.store_account(&stake_pubkey, &stake_account);
|
self.store_account(&stake_pubkey, &stake_account);
|
||||||
vote_account_changed = true;
|
vote_account_changed = true;
|
||||||
|
|
||||||
if voters_reward > 0 {
|
|
||||||
let reward_info = rewards
|
|
||||||
.entry(*vote_pubkey)
|
|
||||||
.or_insert_with(RewardInfo::default);
|
|
||||||
reward_info.lamports += voters_reward as i64;
|
|
||||||
reward_info.post_balance = vote_account.lamports;
|
|
||||||
}
|
|
||||||
|
|
||||||
if stakers_reward > 0 {
|
if stakers_reward > 0 {
|
||||||
let reward_info = rewards
|
rewards.push((
|
||||||
.entry(*stake_pubkey)
|
*stake_pubkey,
|
||||||
.or_insert_with(RewardInfo::default);
|
RewardInfo {
|
||||||
reward_info.lamports += stakers_reward as i64;
|
reward_type: RewardType::Staking,
|
||||||
reward_info.post_balance = stake_account.lamports;
|
lamports: stakers_reward as i64,
|
||||||
|
post_balance: stake_account.lamports,
|
||||||
|
},
|
||||||
|
));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
debug!(
|
debug!(
|
||||||
|
@ -1358,12 +1383,23 @@ impl Bank {
|
||||||
}
|
}
|
||||||
|
|
||||||
if vote_account_changed {
|
if vote_account_changed {
|
||||||
|
let post_balance = vote_account.lamports;
|
||||||
|
let lamports = (post_balance - voters_account_pre_balance) as i64;
|
||||||
|
if lamports != 0 {
|
||||||
|
rewards.push((
|
||||||
|
*vote_pubkey,
|
||||||
|
RewardInfo {
|
||||||
|
reward_type: RewardType::Voting,
|
||||||
|
lamports,
|
||||||
|
post_balance,
|
||||||
|
},
|
||||||
|
));
|
||||||
|
}
|
||||||
self.store_account(&vote_pubkey, &vote_account);
|
self.store_account(&vote_pubkey, &vote_account);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
self.rewards.write().unwrap().append(&mut rewards);
|
||||||
|
|
||||||
assert_eq!(self.rewards, None);
|
|
||||||
self.rewards = Some(rewards.drain().collect());
|
|
||||||
point_value.rewards as f64 / point_value.points as f64
|
point_value.rewards as f64 / point_value.points as f64
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1446,7 +1482,16 @@ impl Bank {
|
||||||
"distributed fee: {} (rounded from: {}, burned: {})",
|
"distributed fee: {} (rounded from: {}, burned: {})",
|
||||||
unburned, collector_fees, burned
|
unburned, collector_fees, burned
|
||||||
);
|
);
|
||||||
self.deposit(&self.collector_id, unburned);
|
|
||||||
|
let post_balance = self.deposit(&self.collector_id, unburned);
|
||||||
|
self.rewards.write().unwrap().push((
|
||||||
|
self.collector_id,
|
||||||
|
RewardInfo {
|
||||||
|
reward_type: RewardType::Fee,
|
||||||
|
lamports: unburned as i64,
|
||||||
|
post_balance,
|
||||||
|
},
|
||||||
|
));
|
||||||
self.capitalization.fetch_sub(burned, Relaxed);
|
self.capitalization.fetch_sub(burned, Relaxed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2621,6 +2666,7 @@ impl Bank {
|
||||||
// holder
|
// holder
|
||||||
let mut leftover_lamports = rent_to_be_distributed - rent_distributed_in_initial_round;
|
let mut leftover_lamports = rent_to_be_distributed - rent_distributed_in_initial_round;
|
||||||
|
|
||||||
|
let mut rewards = vec![];
|
||||||
validator_rent_shares
|
validator_rent_shares
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.for_each(|(pubkey, rent_share)| {
|
.for_each(|(pubkey, rent_share)| {
|
||||||
|
@ -2633,7 +2679,16 @@ impl Bank {
|
||||||
let mut account = self.get_account(&pubkey).unwrap_or_default();
|
let mut account = self.get_account(&pubkey).unwrap_or_default();
|
||||||
account.lamports += rent_to_be_paid;
|
account.lamports += rent_to_be_paid;
|
||||||
self.store_account(&pubkey, &account);
|
self.store_account(&pubkey, &account);
|
||||||
|
rewards.push((
|
||||||
|
pubkey,
|
||||||
|
RewardInfo {
|
||||||
|
reward_type: RewardType::Rent,
|
||||||
|
lamports: rent_to_be_paid as i64,
|
||||||
|
post_balance: account.lamports,
|
||||||
|
},
|
||||||
|
));
|
||||||
});
|
});
|
||||||
|
self.rewards.write().unwrap().append(&mut rewards);
|
||||||
|
|
||||||
if enforce_fix {
|
if enforce_fix {
|
||||||
assert_eq!(leftover_lamports, 0);
|
assert_eq!(leftover_lamports, 0);
|
||||||
|
@ -3224,7 +3279,7 @@ impl Bank {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deposit(&self, pubkey: &Pubkey, lamports: u64) {
|
pub fn deposit(&self, pubkey: &Pubkey, lamports: u64) -> u64 {
|
||||||
let mut account = self.get_account(pubkey).unwrap_or_default();
|
let mut account = self.get_account(pubkey).unwrap_or_default();
|
||||||
|
|
||||||
let should_be_in_new_behavior = match self.cluster_type() {
|
let should_be_in_new_behavior = match self.cluster_type() {
|
||||||
|
@ -3248,6 +3303,7 @@ impl Bank {
|
||||||
|
|
||||||
account.lamports += lamports;
|
account.lamports += lamports;
|
||||||
self.store_account(pubkey, &account);
|
self.store_account(pubkey, &account);
|
||||||
|
account.lamports
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn accounts(&self) -> Arc<Accounts> {
|
pub fn accounts(&self) -> Arc<Accounts> {
|
||||||
|
@ -4688,8 +4744,26 @@ mod tests {
|
||||||
previous_capitalization - current_capitalization,
|
previous_capitalization - current_capitalization,
|
||||||
burned_portion
|
burned_portion
|
||||||
);
|
);
|
||||||
bank.freeze();
|
|
||||||
assert!(bank.calculate_and_verify_capitalization());
|
assert!(bank.calculate_and_verify_capitalization());
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
rent_to_be_distributed,
|
||||||
|
bank.rewards
|
||||||
|
.read()
|
||||||
|
.unwrap()
|
||||||
|
.iter()
|
||||||
|
.map(|(address, reward)| {
|
||||||
|
assert_eq!(reward.reward_type, RewardType::Rent);
|
||||||
|
if *address == validator_2_pubkey {
|
||||||
|
assert_eq!(reward.post_balance, validator_2_portion + 42 - tweak_2);
|
||||||
|
} else if *address == validator_3_pubkey {
|
||||||
|
assert_eq!(reward.post_balance, validator_3_portion + 42);
|
||||||
|
}
|
||||||
|
reward.lamports as u64
|
||||||
|
})
|
||||||
|
.sum::<u64>()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -5676,7 +5750,7 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_bank_update_rewards() {
|
fn test_bank_update_vote_stake_rewards() {
|
||||||
solana_logger::setup();
|
solana_logger::setup();
|
||||||
|
|
||||||
// create a bank that ticks really slowly...
|
// create a bank that ticks really slowly...
|
||||||
|
@ -5709,7 +5783,7 @@ mod tests {
|
||||||
bank.lazy_rent_collection.store(true, Relaxed);
|
bank.lazy_rent_collection.store(true, Relaxed);
|
||||||
|
|
||||||
assert_eq!(bank.capitalization(), 42 * 1_000_000_000);
|
assert_eq!(bank.capitalization(), 42 * 1_000_000_000);
|
||||||
assert_eq!(bank.rewards, None);
|
assert!(bank.rewards.read().unwrap().is_empty());
|
||||||
|
|
||||||
let ((vote_id, mut vote_account), (stake_id, stake_account)) =
|
let ((vote_id, mut vote_account), (stake_id, stake_account)) =
|
||||||
crate::stakes::tests::create_staked_node_accounts(1_0000);
|
crate::stakes::tests::create_staked_node_accounts(1_0000);
|
||||||
|
@ -5782,14 +5856,15 @@ mod tests {
|
||||||
|
|
||||||
// verify validator rewards show up in bank1.rewards vector
|
// verify validator rewards show up in bank1.rewards vector
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
bank1.rewards,
|
*bank1.rewards.read().unwrap(),
|
||||||
Some(vec![(
|
vec![(
|
||||||
stake_id,
|
stake_id,
|
||||||
RewardInfo {
|
RewardInfo {
|
||||||
|
reward_type: RewardType::Staking,
|
||||||
lamports: (rewards.validator_point_value * validator_points as f64) as i64,
|
lamports: (rewards.validator_point_value * validator_points as f64) as i64,
|
||||||
post_balance: bank1.get_balance(&stake_id),
|
post_balance: bank1.get_balance(&stake_id),
|
||||||
}
|
}
|
||||||
)])
|
)]
|
||||||
);
|
);
|
||||||
bank1.freeze();
|
bank1.freeze();
|
||||||
assert!(bank1.calculate_and_verify_capitalization());
|
assert!(bank1.calculate_and_verify_capitalization());
|
||||||
|
@ -5826,7 +5901,7 @@ mod tests {
|
||||||
bank.lazy_rent_collection.store(true, Relaxed);
|
bank.lazy_rent_collection.store(true, Relaxed);
|
||||||
|
|
||||||
assert_eq!(bank.capitalization(), 42 * 1_000_000_000);
|
assert_eq!(bank.capitalization(), 42 * 1_000_000_000);
|
||||||
assert_eq!(bank.rewards, None);
|
assert!(bank.rewards.read().unwrap().is_empty());
|
||||||
|
|
||||||
let vote_id = Pubkey::new_rand();
|
let vote_id = Pubkey::new_rand();
|
||||||
let mut vote_account = vote_state::create_account(&vote_id, &Pubkey::new_rand(), 50, 100);
|
let mut vote_account = vote_state::create_account(&vote_id, &Pubkey::new_rand(), 50, 100);
|
||||||
|
@ -5866,6 +5941,18 @@ mod tests {
|
||||||
|
|
||||||
bank1.freeze();
|
bank1.freeze();
|
||||||
assert!(bank1.calculate_and_verify_capitalization());
|
assert!(bank1.calculate_and_verify_capitalization());
|
||||||
|
|
||||||
|
// verify voting and staking rewards are recorded
|
||||||
|
let rewards = bank1.rewards.read().unwrap();
|
||||||
|
rewards
|
||||||
|
.iter()
|
||||||
|
.find(|(_address, reward)| reward.reward_type == RewardType::Voting)
|
||||||
|
.unwrap();
|
||||||
|
rewards
|
||||||
|
.iter()
|
||||||
|
.find(|(_address, reward)| reward.reward_type == RewardType::Staking)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
bank1.capitalization()
|
bank1.capitalization()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6127,11 +6214,13 @@ mod tests {
|
||||||
|
|
||||||
// Test new account
|
// Test new account
|
||||||
let key = Keypair::new();
|
let key = Keypair::new();
|
||||||
bank.deposit(&key.pubkey(), 10);
|
let new_balance = bank.deposit(&key.pubkey(), 10);
|
||||||
|
assert_eq!(new_balance, 10);
|
||||||
assert_eq!(bank.get_balance(&key.pubkey()), 10);
|
assert_eq!(bank.get_balance(&key.pubkey()), 10);
|
||||||
|
|
||||||
// Existing account
|
// Existing account
|
||||||
bank.deposit(&key.pubkey(), 3);
|
let new_balance = bank.deposit(&key.pubkey(), 3);
|
||||||
|
assert_eq!(new_balance, 13);
|
||||||
assert_eq!(bank.get_balance(&key.pubkey()), 13);
|
assert_eq!(bank.get_balance(&key.pubkey()), 13);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6248,6 +6337,18 @@ mod tests {
|
||||||
// verify capitalization
|
// verify capitalization
|
||||||
assert_eq!(capitalization - expected_fee_burned, bank.capitalization());
|
assert_eq!(capitalization - expected_fee_burned, bank.capitalization());
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
*bank.rewards.read().unwrap(),
|
||||||
|
vec![(
|
||||||
|
leader,
|
||||||
|
RewardInfo {
|
||||||
|
reward_type: RewardType::Fee,
|
||||||
|
lamports: expected_fee_collected as i64,
|
||||||
|
post_balance: initial_balance + expected_fee_collected,
|
||||||
|
}
|
||||||
|
)]
|
||||||
|
);
|
||||||
|
|
||||||
// Verify that an InstructionError collects fees, too
|
// Verify that an InstructionError collects fees, too
|
||||||
let mut bank = Bank::new_from_parent(&Arc::new(bank), &leader, 1);
|
let mut bank = Bank::new_from_parent(&Arc::new(bank), &leader, 1);
|
||||||
let mut tx =
|
let mut tx =
|
||||||
|
@ -6270,6 +6371,18 @@ mod tests {
|
||||||
bank.get_balance(&leader),
|
bank.get_balance(&leader),
|
||||||
initial_balance + 2 * expected_fee_collected
|
initial_balance + 2 * expected_fee_collected
|
||||||
);
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
*bank.rewards.read().unwrap(),
|
||||||
|
vec![(
|
||||||
|
leader,
|
||||||
|
RewardInfo {
|
||||||
|
reward_type: RewardType::Fee,
|
||||||
|
lamports: expected_fee_collected as i64,
|
||||||
|
post_balance: initial_balance + 2 * expected_fee_collected,
|
||||||
|
}
|
||||||
|
)]
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
@ -91,9 +91,20 @@ pub struct Reward {
|
||||||
pub lamports: i64,
|
pub lamports: i64,
|
||||||
#[prost(uint64, tag = "3")]
|
#[prost(uint64, tag = "3")]
|
||||||
pub post_balance: u64,
|
pub post_balance: u64,
|
||||||
|
#[prost(enumeration = "RewardType", tag = "4")]
|
||||||
|
pub reward_type: i32,
|
||||||
}
|
}
|
||||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||||
pub struct UnixTimestamp {
|
pub struct UnixTimestamp {
|
||||||
#[prost(int64, tag = "1")]
|
#[prost(int64, tag = "1")]
|
||||||
pub timestamp: i64,
|
pub timestamp: i64,
|
||||||
}
|
}
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
|
||||||
|
#[repr(i32)]
|
||||||
|
pub enum RewardType {
|
||||||
|
Unspecified = 0,
|
||||||
|
Fee = 1,
|
||||||
|
Rent = 2,
|
||||||
|
Staking = 3,
|
||||||
|
Voting = 4,
|
||||||
|
}
|
||||||
|
|
|
@ -57,10 +57,19 @@ message CompiledInstruction {
|
||||||
bytes data = 3;
|
bytes data = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum RewardType {
|
||||||
|
Unspecified = 0;
|
||||||
|
Fee = 1;
|
||||||
|
Rent = 2;
|
||||||
|
Staking = 3;
|
||||||
|
Voting = 4;
|
||||||
|
}
|
||||||
|
|
||||||
message Reward {
|
message Reward {
|
||||||
string pubkey = 1;
|
string pubkey = 1;
|
||||||
int64 lamports = 2;
|
int64 lamports = 2;
|
||||||
uint64 post_balance = 3;
|
uint64 post_balance = 3;
|
||||||
|
RewardType reward_type = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
message UnixTimestamp {
|
message UnixTimestamp {
|
||||||
|
|
|
@ -7,7 +7,8 @@ use solana_sdk::{
|
||||||
transaction::Transaction,
|
transaction::Transaction,
|
||||||
};
|
};
|
||||||
use solana_transaction_status::{
|
use solana_transaction_status::{
|
||||||
ConfirmedBlock, InnerInstructions, Reward, TransactionStatusMeta, TransactionWithStatusMeta,
|
ConfirmedBlock, InnerInstructions, Reward, RewardType, TransactionStatusMeta,
|
||||||
|
TransactionWithStatusMeta,
|
||||||
};
|
};
|
||||||
use std::convert::{TryFrom, TryInto};
|
use std::convert::{TryFrom, TryInto};
|
||||||
|
|
||||||
|
@ -24,6 +25,13 @@ impl From<Reward> for generated::Reward {
|
||||||
pubkey: reward.pubkey,
|
pubkey: reward.pubkey,
|
||||||
lamports: reward.lamports,
|
lamports: reward.lamports,
|
||||||
post_balance: reward.post_balance,
|
post_balance: reward.post_balance,
|
||||||
|
reward_type: match reward.reward_type {
|
||||||
|
None => generated::RewardType::Unspecified,
|
||||||
|
Some(RewardType::Fee) => generated::RewardType::Fee,
|
||||||
|
Some(RewardType::Rent) => generated::RewardType::Rent,
|
||||||
|
Some(RewardType::Staking) => generated::RewardType::Staking,
|
||||||
|
Some(RewardType::Voting) => generated::RewardType::Voting,
|
||||||
|
} as i32,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -34,6 +42,14 @@ impl From<generated::Reward> for Reward {
|
||||||
pubkey: reward.pubkey,
|
pubkey: reward.pubkey,
|
||||||
lamports: reward.lamports,
|
lamports: reward.lamports,
|
||||||
post_balance: reward.post_balance,
|
post_balance: reward.post_balance,
|
||||||
|
reward_type: match reward.reward_type {
|
||||||
|
0 => None,
|
||||||
|
1 => Some(RewardType::Fee),
|
||||||
|
2 => Some(RewardType::Rent),
|
||||||
|
3 => Some(RewardType::Voting),
|
||||||
|
4 => Some(RewardType::Staking),
|
||||||
|
_ => None,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -222,6 +222,7 @@ impl From<StoredConfirmedBlockReward> for Reward {
|
||||||
pubkey,
|
pubkey,
|
||||||
lamports,
|
lamports,
|
||||||
post_balance: 0,
|
post_balance: 0,
|
||||||
|
reward_type: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@ serde_derive = "1.0.103"
|
||||||
serde_json = "1.0.56"
|
serde_json = "1.0.56"
|
||||||
solana-account-decoder = { path = "../account-decoder", version = "1.5.0" }
|
solana-account-decoder = { path = "../account-decoder", version = "1.5.0" }
|
||||||
solana-sdk = { path = "../sdk", version = "1.5.0" }
|
solana-sdk = { path = "../sdk", version = "1.5.0" }
|
||||||
|
solana-runtime = { path = "../runtime", version = "1.5.0" }
|
||||||
solana-stake-program = { path = "../programs/stake", version = "1.5.0" }
|
solana-stake-program = { path = "../programs/stake", version = "1.5.0" }
|
||||||
solana-vote-program = { path = "../programs/vote", version = "1.5.0" }
|
solana-vote-program = { path = "../programs/vote", version = "1.5.0" }
|
||||||
spl-memo-v1-0 = { package = "spl-memo", version = "=1.0.7", features = ["skip-no-mangle"] }
|
spl-memo-v1-0 = { package = "spl-memo", version = "=1.0.7", features = ["skip-no-mangle"] }
|
||||||
|
|
|
@ -11,6 +11,7 @@ use crate::{
|
||||||
parse_accounts::{parse_accounts, ParsedAccount},
|
parse_accounts::{parse_accounts, ParsedAccount},
|
||||||
parse_instruction::{parse, ParsedInstruction},
|
parse_instruction::{parse, ParsedInstruction},
|
||||||
};
|
};
|
||||||
|
pub use solana_runtime::bank::RewardType;
|
||||||
use solana_sdk::{
|
use solana_sdk::{
|
||||||
clock::{Slot, UnixTimestamp},
|
clock::{Slot, UnixTimestamp},
|
||||||
commitment_config::CommitmentConfig,
|
commitment_config::CommitmentConfig,
|
||||||
|
@ -241,6 +242,8 @@ pub struct Reward {
|
||||||
pub lamports: i64,
|
pub lamports: i64,
|
||||||
#[serde(deserialize_with = "default_on_eof")]
|
#[serde(deserialize_with = "default_on_eof")]
|
||||||
pub post_balance: u64, // Account balance in lamports after `lamports` was applied
|
pub post_balance: u64, // Account balance in lamports after `lamports` was applied
|
||||||
|
#[serde(default, deserialize_with = "default_on_eof")]
|
||||||
|
pub reward_type: Option<RewardType>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type Rewards = Vec<Reward>;
|
pub type Rewards = Vec<Reward>;
|
||||||
|
|
Loading…
Reference in New Issue