diff --git a/account-decoder/src/parse_sysvar.rs b/account-decoder/src/parse_sysvar.rs index 3fda8e8560c..35746949c7f 100644 --- a/account-decoder/src/parse_sysvar.rs +++ b/account-decoder/src/parse_sysvar.rs @@ -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, @@ -97,24 +96,7 @@ pub fn parse_sysvar(data: &[u8], pubkey: &Pubkey) -> Result(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( @@ -138,7 +120,6 @@ pub enum SysvarAccountType { StakeHistory(Vec), LastRestartSlot(UiLastRestartSlot), EpochRewards(EpochRewards), - EpochRewardsPartitionData(UiEpochRewardsPartitionData), } #[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Default)] @@ -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)] diff --git a/rpc/src/rpc.rs b/rpc/src/rpc.rs index 16d78a913bc..5cc5b82344e 100644 --- a/rpc/src/rpc.rs +++ b/rpc/src/rpc.rs @@ -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}, @@ -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, @@ -523,38 +519,6 @@ impl JsonRpcRequestProcessor { }) } - async fn get_reward_map( - &self, - slot: Slot, - addresses: &[String], - reward_type_filter: &F, - config: &RpcEpochConfig, - ) -> Result> - 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, @@ -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 { @@ -592,8 +554,6 @@ 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? @@ -601,94 +561,44 @@ impl JsonRpcRequestProcessor { .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 = { - let addresses: Vec = - 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> = 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 = 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 = 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, @@ -697,6 +607,7 @@ impl JsonRpcRequestProcessor { None }) .collect(); + Ok(rewards) } diff --git a/runtime/src/bank.rs b/runtime/src/bank.rs index 94e7bf979ff..5f66968040e 100644 --- a/runtime/src/bank.rs +++ b/runtime/src/bank.rs @@ -144,10 +144,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}, @@ -904,7 +900,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 @@ -922,8 +917,6 @@ struct CalculateRewardsAndDistributeVoteRewardsResult { distributed_rewards: u64, /// stake rewards that still need to be distributed, grouped by partition stake_rewards_by_partition: Vec, - /// blockhash of parent, used to create EpochRewardsHasher - parent_blockhash: Hash, } pub(crate) type StakeRewards = Vec; @@ -1615,7 +1608,6 @@ impl Bank { total_rewards, distributed_rewards, stake_rewards_by_partition, - parent_blockhash, } = self.calculate_rewards_and_distribute_vote_rewards( parent_epoch, reward_calc_tracer, @@ -1623,11 +1615,9 @@ impl Bank { 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); @@ -1635,8 +1625,6 @@ impl Bank { // (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), @@ -2402,7 +2390,6 @@ impl Bank { foundation_rate, prev_epoch_duration_in_years, capitalization, - parent_blockhash, } } @@ -2423,7 +2410,6 @@ impl Bank { foundation_rate, prev_epoch_duration_in_years, capitalization, - parent_blockhash, } = self.calculate_rewards_for_partitioning( prev_epoch, reward_calc_tracer, @@ -2493,7 +2479,6 @@ impl Bank { total_rewards: validator_rewards_paid + total_stake_rewards_lamports, distributed_rewards: validator_rewards_paid, stake_rewards_by_partition, - parent_blockhash, } } @@ -3607,40 +3592,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(); - - info!( - "create epoch rewards partition data account {} {address} \ - {epoch_rewards_partition_data:?}", - self.slot - ); - - // Skip storing data account when we are testing partitioned - // rewards but feature is not yet active - if !self.force_partition_rewards_in_first_block_of_epoch() { - 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| { diff --git a/runtime/src/epoch_rewards_hasher.rs b/runtime/src/epoch_rewards_hasher.rs index 120bb0c2c98..b594b05a5cf 100644 --- a/runtime/src/epoch_rewards_hasher.rs +++ b/runtime/src/epoch_rewards_hasher.rs @@ -9,7 +9,7 @@ pub(crate) fn hash_rewards_into_partitions( num_partitions: usize, ) -> Vec { let hasher = EpochRewardsHasher::new(num_partitions, parent_blockhash); - let mut rewards = vec![vec![]; num_partitions]; + let mut result = vec![vec![]; num_partitions]; for reward in stake_rewards { // clone here so the hasher's state is re-used on each call to `hash_address_to_partition`. @@ -18,9 +18,9 @@ pub(crate) fn hash_rewards_into_partitions( let partition_index = hasher .clone() .hash_address_to_partition(&reward.stake_pubkey); - rewards[partition_index].push(reward); + result[partition_index].push(reward); } - rewards + result } #[cfg(test)] diff --git a/sdk/program/src/epoch_rewards_partition_data.rs b/sdk/program/src/epoch_rewards_partition_data.rs deleted file mode 100644 index 2ff511af8fb..00000000000 --- a/sdk/program/src/epoch_rewards_partition_data.rs +++ /dev/null @@ -1,39 +0,0 @@ -use { - crate::{hash::Hash, pubkey::Pubkey}, - serde_derive::{Deserialize, Serialize}, -}; - -#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone)] -pub enum EpochRewardsPartitionDataVersion { - V0(PartitionData), -} - -impl EpochRewardsPartitionDataVersion { - pub fn get_hasher_kind(&self) -> HasherKind { - match self { - EpochRewardsPartitionDataVersion::V0(_) => HasherKind::Sip13, - } - } -} - -#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone)] -pub enum HasherKind { - Sip13, -} - -/// Data about a rewards partitions for an epoch -#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone)] -pub struct PartitionData { - /// Number of partitions used for epoch rewards this epoch - pub num_partitions: usize, - /// Blockhash of the last block of the previous epoch, used to create EpochRewardsHasher - pub parent_blockhash: Hash, -} - -pub fn get_epoch_rewards_partition_data_address(epoch: u64) -> Pubkey { - let (address, _bump_seed) = Pubkey::find_program_address( - &[b"EpochRewards", b"PartitionData", &epoch.to_le_bytes()], - &crate::sysvar::id(), - ); - address -} diff --git a/sdk/program/src/lib.rs b/sdk/program/src/lib.rs index 016585d403a..54de9d81720 100644 --- a/sdk/program/src/lib.rs +++ b/sdk/program/src/lib.rs @@ -491,7 +491,6 @@ pub mod ed25519_program; pub mod entrypoint; pub mod entrypoint_deprecated; pub mod epoch_rewards; -pub mod epoch_rewards_partition_data; pub mod epoch_schedule; pub mod feature; pub mod fee_calculator; diff --git a/sdk/src/lib.rs b/sdk/src/lib.rs index e64d6ddc57d..4bf36a5d271 100644 --- a/sdk/src/lib.rs +++ b/sdk/src/lib.rs @@ -48,8 +48,8 @@ pub use solana_program::{ account_info, address_lookup_table, alt_bn128, big_mod_exp, blake3, borsh, borsh0_10, borsh0_9, borsh1, bpf_loader, bpf_loader_deprecated, bpf_loader_upgradeable, clock, config, custom_heap_default, custom_panic_default, debug_account_data, declare_deprecated_sysvar_id, - declare_sysvar_id, decode_error, ed25519_program, epoch_rewards, epoch_rewards_partition_data, - epoch_schedule, fee_calculator, impl_sysvar_get, incinerator, instruction, keccak, lamports, + declare_sysvar_id, decode_error, ed25519_program, epoch_rewards, epoch_schedule, + fee_calculator, impl_sysvar_get, incinerator, instruction, keccak, lamports, loader_instruction, loader_upgradeable_instruction, loader_v4, loader_v4_instruction, message, msg, native_token, nonce, poseidon, program, program_error, program_memory, program_option, program_pack, rent, sanitize, sdk_ids, secp256k1_program, secp256k1_recover, serde_varint, diff --git a/validator/src/bin/solana-test-validator.rs b/validator/src/bin/solana-test-validator.rs index 3c851e7788e..aee5fc039df 100644 --- a/validator/src/bin/solana-test-validator.rs +++ b/validator/src/bin/solana-test-validator.rs @@ -19,6 +19,7 @@ use { account::AccountSharedData, clock::Slot, epoch_schedule::EpochSchedule, + feature_set, native_token::sol_to_lamports, pubkey::Pubkey, rent::Rent, @@ -348,7 +349,9 @@ fn main() { exit(1); }); - let features_to_deactivate = pubkeys_of(&matches, "deactivate_feature").unwrap_or_default(); + let mut features_to_deactivate = pubkeys_of(&matches, "deactivate_feature").unwrap_or_default(); + // Remove this when client support is ready for the enable_partitioned_epoch_reward feature + features_to_deactivate.push(feature_set::enable_partitioned_epoch_reward::id()); if TestValidatorGenesis::ledger_exists(&ledger_path) { for (name, long) in &[