Skip to content
This repository was archived by the owner on Jan 22, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 1 addition & 28 deletions account-decoder/src/parse_sysvar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ use {
bv::BitVec,
solana_sdk::{
clock::{Clock, Epoch, Slot, UnixTimestamp},
epoch_rewards_partition_data::EpochRewardsPartitionDataVersion,
epoch_schedule::EpochSchedule,
pubkey::Pubkey,
rent::Rent,
Expand Down Expand Up @@ -97,24 +96,7 @@ pub fn parse_sysvar(data: &[u8], pubkey: &Pubkey) -> Result<SysvarAccountType, P
.ok()
.map(SysvarAccountType::EpochRewards)
} else {
// EpochRewards PartitionData accounts are owned by the sysvar
// program, but have dynamically generated addresses. Test on
// whether account content deserializes properly.
if let Ok(epoch_rewards_partition_data) =
deserialize::<EpochRewardsPartitionDataVersion>(data)
{
let EpochRewardsPartitionDataVersion::V0(partition_data) =
epoch_rewards_partition_data;
Some(SysvarAccountType::EpochRewardsPartitionData(
UiEpochRewardsPartitionData {
version: 0,
num_partitions: partition_data.num_partitions as u64,
parent_blockhash: partition_data.parent_blockhash.to_string(),
},
))
} else {
None
}
None
}
};
parsed_account.ok_or(ParseAccountError::AccountNotParsable(
Expand All @@ -138,7 +120,6 @@ pub enum SysvarAccountType {
StakeHistory(Vec<UiStakeHistoryEntry>),
LastRestartSlot(UiLastRestartSlot),
EpochRewards(EpochRewards),
EpochRewardsPartitionData(UiEpochRewardsPartitionData),
}

#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Default)]
Expand Down Expand Up @@ -258,14 +239,6 @@ pub struct UiLastRestartSlot {
pub last_restart_slot: Slot,
}

#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Default)]
#[serde(rename_all = "camelCase")]
pub struct UiEpochRewardsPartitionData {
pub version: u32,
pub num_partitions: u64,
pub parent_blockhash: String,
}

#[cfg(test)]
mod test {
#[allow(deprecated)]
Expand Down
157 changes: 34 additions & 123 deletions rpc/src/rpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use {
base64::{prelude::BASE64_STANDARD, Engine},
bincode::{config::Options, serialize},
crossbeam_channel::{unbounded, Receiver, Sender},
jsonrpc_core::{futures::future, types::error, BoxFuture, Error, ErrorCode, Metadata, Result},
jsonrpc_core::{futures::future, types::error, BoxFuture, Error, Metadata, Result},
jsonrpc_derive::rpc,
solana_account_decoder::{
parse_token::{is_known_spl_token_id, token_amount_to_ui_amount, UiTokenAmount},
Expand Down Expand Up @@ -62,10 +62,6 @@ use {
clock::{Slot, UnixTimestamp, MAX_RECENT_BLOCKHASHES},
commitment_config::{CommitmentConfig, CommitmentLevel},
epoch_info::EpochInfo,
epoch_rewards_hasher::EpochRewardsHasher,
epoch_rewards_partition_data::{
get_epoch_rewards_partition_data_address, EpochRewardsPartitionDataVersion,
},
epoch_schedule::EpochSchedule,
exit::Exit,
feature_set,
Expand Down Expand Up @@ -523,38 +519,6 @@ impl JsonRpcRequestProcessor {
})
}

async fn get_reward_map<F>(
&self,
slot: Slot,
addresses: &[String],
reward_type_filter: &F,
config: &RpcEpochConfig,
) -> Result<HashMap<String, (Reward, Slot)>>
where
F: Fn(RewardType) -> bool,
{
let Ok(Some(block)) = self
.get_block(
slot,
Some(RpcBlockConfig::rewards_with_commitment(config.commitment).into()),
)
.await
else {
return Err(RpcCustomError::BlockNotAvailable { slot }.into());
};

Ok(block
.rewards
.unwrap_or_default()
.into_iter()
.filter(|reward| {
reward.reward_type.is_some_and(reward_type_filter)
&& addresses.contains(&reward.pubkey)
})
.map(|reward| (reward.clone().pubkey, (reward, slot)))
.collect())
}

pub async fn get_inflation_reward(
&self,
addresses: Vec<Pubkey>,
Expand All @@ -563,20 +527,18 @@ impl JsonRpcRequestProcessor {
let config = config.unwrap_or_default();
let epoch_schedule = self.get_epoch_schedule();
let first_available_block = self.get_first_available_block().await;
let slot_context = RpcContextConfig {
commitment: config.commitment,
min_context_slot: config.min_context_slot,
};
let epoch = match config.epoch {
Some(epoch) => epoch,
None => epoch_schedule
.get_epoch(self.get_slot(slot_context)?)
.get_epoch(self.get_slot(RpcContextConfig {
commitment: config.commitment,
min_context_slot: config.min_context_slot,
})?)
.saturating_sub(1),
};
// Rewards for this epoch are found in the first confirmed block of the next epoch
let rewards_epoch = epoch.saturating_add(1);
let first_slot_in_epoch = epoch_schedule.get_first_slot_in_epoch(rewards_epoch);

// Rewards for this epoch are found in the first confirmed block of the next epoch
let first_slot_in_epoch = epoch_schedule.get_first_slot_in_epoch(epoch.saturating_add(1));
if first_slot_in_epoch < first_available_block {
if self.bigtable_ledger_storage.is_some() {
return Err(RpcCustomError::LongTermStorageSlotSkipped {
Expand All @@ -592,103 +554,51 @@ impl JsonRpcRequestProcessor {
}
}

let bank = self.get_bank_with_config(slot_context)?;

let first_confirmed_block_in_epoch = *self
.get_blocks_with_limit(first_slot_in_epoch, 1, config.commitment)
.await?
.first()
.ok_or(RpcCustomError::BlockNotAvailable {
slot: first_slot_in_epoch,
})?;
let partitioned_epoch_reward_enabled_slot = bank
.feature_set
.activated_slot(&feature_set::enable_partitioned_epoch_reward::id());
let partitioned_epoch_reward_enabled = partitioned_epoch_reward_enabled_slot
.map(|slot| slot <= first_confirmed_block_in_epoch)
.unwrap_or(false);

let mut reward_map: HashMap<String, (Reward, Slot)> = {
let addresses: Vec<String> =
addresses.iter().map(|pubkey| pubkey.to_string()).collect();

self.get_reward_map(
let Ok(Some(first_confirmed_block)) = self
.get_block(
first_confirmed_block_in_epoch,
&addresses,
&|reward_type| -> bool {
reward_type == RewardType::Voting
|| (!partitioned_epoch_reward_enabled && reward_type == RewardType::Staking)
},
&config,
Some(RpcBlockConfig::rewards_with_commitment(config.commitment).into()),
)
.await?
.await
else {
return Err(RpcCustomError::BlockNotAvailable {
slot: first_confirmed_block_in_epoch,
}
.into());
};

if partitioned_epoch_reward_enabled {
let partition_data_address = get_epoch_rewards_partition_data_address(rewards_epoch);
let partition_data_account =
bank.get_account(&partition_data_address)
.ok_or_else(|| Error {
code: ErrorCode::InternalError,
message: format!(
"Partition data account not found for epoch {:?} at {:?}",
epoch, partition_data_address
),
data: None,
})?;
let EpochRewardsPartitionDataVersion::V0(partition_data) =
bincode::deserialize(partition_data_account.data())
.map_err(|_| Error::internal_error())?;
let hasher = EpochRewardsHasher::new(
partition_data.num_partitions,
&partition_data.parent_blockhash,
);
let mut partition_index_addresses: HashMap<usize, Vec<String>> = HashMap::new();
for address in addresses.iter() {
let address_string = address.to_string();
// Skip this address if (Voting) rewards were already found in
// the first block of the epoch
if !reward_map.contains_key(&address_string) {
let partition_index = hasher.clone().hash_address_to_partition(address);
partition_index_addresses
.entry(partition_index)
.and_modify(|list| list.push(address_string.clone()))
.or_insert(vec![address_string]);
}
}
let addresses: Vec<String> = addresses
.into_iter()
.map(|pubkey| pubkey.to_string())
.collect();

let block_list = self
.get_blocks_with_limit(
first_confirmed_block_in_epoch + 1,
partition_data.num_partitions,
config.commitment,
)
.await?;

for (partition_index, addresses) in partition_index_addresses.iter() {
let slot = *block_list
.get(*partition_index)
.ok_or_else(Error::internal_error)?;

let index_reward_map = self
.get_reward_map(
slot,
addresses,
&|reward_type| -> bool { reward_type == RewardType::Staking },
&config,
)
.await?;
reward_map.extend(index_reward_map);
}
}
let reward_hash: HashMap<String, Reward> = first_confirmed_block
.rewards
.unwrap_or_default()
.into_iter()
.filter_map(|reward| match reward.reward_type? {
RewardType::Staking | RewardType::Voting => addresses
.contains(&reward.pubkey)
.then(|| (reward.clone().pubkey, reward)),
_ => None,
})
.collect();

let rewards = addresses
.iter()
.map(|address| {
if let Some((reward, slot)) = reward_map.get(&address.to_string()) {
if let Some(reward) = reward_hash.get(address) {
return Some(RpcInflationReward {
epoch,
effective_slot: *slot,
effective_slot: first_confirmed_block_in_epoch,
amount: reward.lamports.unsigned_abs(),
post_balance: reward.post_balance,
commission: reward.commission,
Expand All @@ -697,6 +607,7 @@ impl JsonRpcRequestProcessor {
None
})
.collect();

Ok(rewards)
}

Expand Down
40 changes: 1 addition & 39 deletions runtime/src/bank.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,10 +139,6 @@ use {
UPDATED_HASHES_PER_TICK4, UPDATED_HASHES_PER_TICK5, UPDATED_HASHES_PER_TICK6,
},
epoch_info::EpochInfo,
epoch_rewards_partition_data::{
get_epoch_rewards_partition_data_address, EpochRewardsPartitionDataVersion,
PartitionData,
},
epoch_schedule::EpochSchedule,
feature,
feature_set::{self, include_loaded_accounts_data_size_in_fee_calculation, FeatureSet},
Expand Down Expand Up @@ -894,7 +890,6 @@ struct PartitionedRewardsCalculation {
foundation_rate: f64,
prev_epoch_duration_in_years: f64,
capitalization: u64,
parent_blockhash: Hash,
}

/// result of calculating the stake rewards at beginning of new epoch
Expand All @@ -912,8 +907,6 @@ struct CalculateRewardsAndDistributeVoteRewardsResult {
distributed_rewards: u64,
/// stake rewards that still need to be distributed, grouped by partition
stake_rewards_by_partition: Vec<StakeRewards>,
/// blockhash of parent, used to create EpochRewardsHasher
parent_blockhash: Hash,
}

pub(crate) type StakeRewards = Vec<StakeReward>;
Expand Down Expand Up @@ -1602,28 +1595,23 @@ impl Bank {
total_rewards,
distributed_rewards,
stake_rewards_by_partition,
parent_blockhash,
} = self.calculate_rewards_and_distribute_vote_rewards(
parent_epoch,
reward_calc_tracer,
thread_pool,
rewards_metrics,
);

let num_partitions = stake_rewards_by_partition.len();

let slot = self.slot();
let credit_start = self.block_height() + self.get_reward_calculation_num_blocks();
let credit_end_exclusive = credit_start + num_partitions as u64;
let credit_end_exclusive = credit_start + stake_rewards_by_partition.len() as u64;

self.set_epoch_reward_status_active(stake_rewards_by_partition);

// create EpochRewards sysvar that holds the balance of undistributed rewards with
// (total_rewards, distributed_rewards, credit_end_exclusive), total capital will increase by (total_rewards - distributed_rewards)
self.create_epoch_rewards_sysvar(total_rewards, distributed_rewards, credit_end_exclusive);

self.create_epoch_rewards_partition_data_account(num_partitions, parent_blockhash);

datapoint_info!(
"epoch-rewards-status-update",
("start_slot", slot, i64),
Expand Down Expand Up @@ -2389,7 +2377,6 @@ impl Bank {
foundation_rate,
prev_epoch_duration_in_years,
capitalization,
parent_blockhash,
}
}

Expand All @@ -2410,7 +2397,6 @@ impl Bank {
foundation_rate,
prev_epoch_duration_in_years,
capitalization,
parent_blockhash,
} = self.calculate_rewards_for_partitioning(
prev_epoch,
reward_calc_tracer,
Expand Down Expand Up @@ -2480,7 +2466,6 @@ impl Bank {
total_rewards: validator_rewards_paid + total_stake_rewards_lamports,
distributed_rewards: validator_rewards_paid,
stake_rewards_by_partition,
parent_blockhash,
}
}

Expand Down Expand Up @@ -3594,29 +3579,6 @@ impl Bank {
self.log_epoch_rewards_sysvar("update");
}

/// Create the persistent PDA containing the epoch-rewards data
fn create_epoch_rewards_partition_data_account(
&self,
num_partitions: usize,
parent_blockhash: Hash,
) {
let epoch_rewards_partition_data = EpochRewardsPartitionDataVersion::V0(PartitionData {
num_partitions,
parent_blockhash,
});
let address = get_epoch_rewards_partition_data_address(self.epoch());

let data_len = bincode::serialized_size(&epoch_rewards_partition_data).unwrap() as usize;
let account_balance = self.get_minimum_balance_for_rent_exemption(data_len);
let new_account = AccountSharedData::new_data(
account_balance,
&epoch_rewards_partition_data,
&solana_sdk::sysvar::id(),
)
.unwrap();
self.store_account_and_update_capitalization(&address, &new_account);
}

fn update_recent_blockhashes_locked(&self, locked_blockhash_queue: &BlockhashQueue) {
#[allow(deprecated)]
self.update_sysvar_account(&sysvar::recent_blockhashes::id(), |account| {
Expand Down
Loading