Explorar el Código

Clean up Partitioned Epoch Rewards feature logic (#4186)

* Remove feature from syscall logic

* Remove is_partitioned_rewards_code_enabled

* Update test_bank_hash_consistency, which runs with all features off

* Fixup test_bank_update_rewards_determinism

* Remove is_partitioned_rewards_feature_enabled

* Remove feature-gate logic

* Remove superfluous total_rewards pass-through

* Start removing old rewards logic: update_rewards_with_thread_pool and PER compare fns

* Remove more old rewards logic: helper fns; and fixup tests

* Remove more old rewards logic: StakesCache helpers

* Remove remaining old rewards logic: type aliases and helper structs

* remove partitioned reward test code

* Remove superfluous test attribute

Co-authored-by: Brooks <brooks@prumo.org>

---------

Co-authored-by: HaoranYi <haoran.yi@anza.xyz>
Co-authored-by: Tyera <tyera@solana.com>
Co-authored-by: Brooks <brooks@prumo.org>
Tyera hace 10 meses
padre
commit
5662eeeb9d

+ 7 - 9
accounts-db/src/accounts_db.rs

@@ -66,7 +66,9 @@ use {
         cache_hash_data::{CacheHashData, DeletionPolicy as CacheHashDeletionPolicy},
         contains::Contains,
         epoch_accounts_hash::EpochAccountsHashManager,
-        partitioned_rewards::{PartitionedEpochRewardsConfig, TestPartitionedEpochRewards},
+        partitioned_rewards::{
+            PartitionedEpochRewardsConfig, DEFAULT_PARTITIONED_EPOCH_REWARDS_CONFIG,
+        },
         read_only_accounts_cache::ReadOnlyAccountsCache,
         sorted_storages::SortedStorages,
         storable_accounts::{StorableAccounts, StorableAccountsBySlot},
@@ -506,7 +508,7 @@ pub const ACCOUNTS_DB_CONFIG_FOR_TESTING: AccountsDbConfig = AccountsDbConfig {
     skip_initial_hash_calc: false,
     exhaustively_verify_refcounts: false,
     create_ancient_storage: CreateAncientStorage::Pack,
-    test_partitioned_epoch_rewards: TestPartitionedEpochRewards::CompareResults,
+    partitioned_epoch_rewards_config: DEFAULT_PARTITIONED_EPOCH_REWARDS_CONFIG,
     test_skip_rewrites_but_include_in_bank_hash: false,
     storage_access: StorageAccess::Mmap,
     scan_filter_for_shrinking: ScanFilter::OnlyAbnormalWithVerify,
@@ -532,7 +534,7 @@ pub const ACCOUNTS_DB_CONFIG_FOR_BENCHMARKS: AccountsDbConfig = AccountsDbConfig
     skip_initial_hash_calc: false,
     exhaustively_verify_refcounts: false,
     create_ancient_storage: CreateAncientStorage::Pack,
-    test_partitioned_epoch_rewards: TestPartitionedEpochRewards::None,
+    partitioned_epoch_rewards_config: DEFAULT_PARTITIONED_EPOCH_REWARDS_CONFIG,
     test_skip_rewrites_but_include_in_bank_hash: false,
     storage_access: StorageAccess::Mmap,
     scan_filter_for_shrinking: ScanFilter::OnlyAbnormalWithVerify,
@@ -661,7 +663,7 @@ pub struct AccountsDbConfig {
     pub exhaustively_verify_refcounts: bool,
     /// how to create ancient storages
     pub create_ancient_storage: CreateAncientStorage,
-    pub test_partitioned_epoch_rewards: TestPartitionedEpochRewards,
+    pub partitioned_epoch_rewards_config: PartitionedEpochRewardsConfig,
     pub storage_access: StorageAccess,
     pub scan_filter_for_shrinking: ScanFilter,
     pub enable_experimental_accumulator_hash: bool,
@@ -1964,10 +1966,6 @@ impl AccountsDb {
             accounts_hash_cache_path
         });
 
-        let test_partitioned_epoch_rewards = accounts_db_config.test_partitioned_epoch_rewards;
-        let partitioned_epoch_rewards_config: PartitionedEpochRewardsConfig =
-            PartitionedEpochRewardsConfig::new(test_partitioned_epoch_rewards);
-
         let read_cache_size = accounts_db_config.read_cache_limit_bytes.unwrap_or((
             Self::DEFAULT_MAX_READ_ONLY_CACHE_DATA_SIZE_LO,
             Self::DEFAULT_MAX_READ_ONLY_CACHE_DATA_SIZE_HI,
@@ -2030,7 +2028,7 @@ impl AccountsDb {
                 Self::READ_ONLY_CACHE_MS_TO_SKIP_LRU_UPDATE,
             ),
             write_cache_limit_bytes: accounts_db_config.write_cache_limit_bytes,
-            partitioned_epoch_rewards_config,
+            partitioned_epoch_rewards_config: accounts_db_config.partitioned_epoch_rewards_config,
             exhaustively_verify_refcounts: accounts_db_config.exhaustively_verify_refcounts,
             test_skip_rewrites_but_include_in_bank_hash: accounts_db_config
                 .test_skip_rewrites_but_include_in_bank_hash,

+ 17 - 76
accounts-db/src/partitioned_rewards.rs

@@ -1,98 +1,39 @@
 //! Code related to partitioned rewards distribution
 
-#[derive(Debug)]
+/// # stake accounts to store in one block during partitioned reward interval
+/// Target to store 64 rewards per entry/tick in a block. A block has a minimum of 64
+/// entries/tick. This gives 4096 total rewards to store in one block.
+/// This constant affects consensus.
+const MAX_PARTITIONED_REWARDS_PER_BLOCK: u64 = 4096;
+
+#[derive(Debug, Clone, Copy)]
 /// Configuration options for partitioned epoch rewards.
-/// This struct allows various forms of testing, especially prior to feature activation.
 pub struct PartitionedEpochRewardsConfig {
     /// number of stake accounts to store in one block during partitioned reward interval
     /// normally, this is a number tuned for reasonable performance, such as 4096 accounts/block
-    /// if force_one_slot_partitioned_rewards, this will usually be u64::MAX so that all stake accounts are written in the first block
     pub stake_account_stores_per_block: u64,
-    /// if true, end of epoch bank rewards will force using partitioned rewards distribution.
-    /// see `set_test_enable_partitioned_rewards`
-    pub test_enable_partitioned_rewards: bool,
-    /// if true, end of epoch non-partitioned bank rewards will test the partitioned rewards distribution vote and stake accounts
-    /// This has a significant performance impact on the first slot in each new epoch.
-    pub test_compare_partitioned_epoch_rewards: bool,
 }
 
+/// Convenient constant for default partitioned epoch rewards configuration
+/// used for benchmarks and tests.
+pub const DEFAULT_PARTITIONED_EPOCH_REWARDS_CONFIG: PartitionedEpochRewardsConfig =
+    PartitionedEpochRewardsConfig {
+        stake_account_stores_per_block: MAX_PARTITIONED_REWARDS_PER_BLOCK,
+    };
+
 impl Default for PartitionedEpochRewardsConfig {
     fn default() -> Self {
         Self {
-            // # stake accounts to store in one block during partitioned reward interval
-            // Target to store 64 rewards per entry/tick in a block. A block has a minimum of 64
-            // entries/tick. This gives 4096 total rewards to store in one block.
-            // This constant affects consensus.
-            stake_account_stores_per_block: 4096,
-            test_enable_partitioned_rewards: false,
-            test_compare_partitioned_epoch_rewards: false,
+            stake_account_stores_per_block: MAX_PARTITIONED_REWARDS_PER_BLOCK,
         }
     }
 }
 
-#[derive(Debug, Default, Clone, Copy)]
-pub enum TestPartitionedEpochRewards {
-    #[default]
-    None,
-    CompareResults,
-    ForcePartitionedEpochRewardsInOneBlock,
-    PartitionedEpochRewardsConfigRewardBlocks {
-        stake_account_stores_per_block: u64,
-    },
-}
-
 impl PartitionedEpochRewardsConfig {
-    pub fn new(test: TestPartitionedEpochRewards) -> Self {
-        match test {
-            TestPartitionedEpochRewards::None => Self::default(),
-            TestPartitionedEpochRewards::CompareResults => {
-                Self::set_test_compare_partitioned_epoch_rewards()
-            }
-            TestPartitionedEpochRewards::ForcePartitionedEpochRewardsInOneBlock => {
-                Self::set_test_enable_partitioned_rewards()
-            }
-            TestPartitionedEpochRewards::PartitionedEpochRewardsConfigRewardBlocks {
-                    stake_account_stores_per_block,
-            } => {
-                Self::set_test_enable_partitioned_rewards_with_custom_number_of_stake_accounts_per_block(
-                    stake_account_stores_per_block
-                )
-            }
-        }
-    }
-
-    /// All rewards will be distributed in the first block in the epoch, matching
-    /// consensus for the non-partitioned rewards, but running all the partitioned rewards
-    /// code.
-    fn set_test_enable_partitioned_rewards() -> Self {
-        Self {
-            stake_account_stores_per_block: u64::MAX,
-            test_enable_partitioned_rewards: true,
-            // irrelevant if we are not running old code path
-            test_compare_partitioned_epoch_rewards: false,
-        }
-    }
-
-    /// All rewards will be distributed in the first block in the epoch as normal.
-    /// Then, the partitioned rewards code will calculate expected results and compare to
-    /// the old code path's results.
-    fn set_test_compare_partitioned_epoch_rewards() -> Self {
-        Self {
-            test_compare_partitioned_epoch_rewards: true,
-            ..PartitionedEpochRewardsConfig::default()
-        }
-    }
-
-    /// A method that configures how many reward reward calculation blocks and how many stake
-    /// accounts to store per reward block.
-    fn set_test_enable_partitioned_rewards_with_custom_number_of_stake_accounts_per_block(
-        stake_account_stores_per_block: u64,
-    ) -> Self {
+    /// Only for tests and benchmarks
+    pub fn new_for_test(stake_account_stores_per_block: u64) -> Self {
         Self {
             stake_account_stores_per_block,
-            test_enable_partitioned_rewards: true,
-            // irrelevant if we are not running old code path
-            test_compare_partitioned_epoch_rewards: false,
         }
     }
 }

+ 0 - 11
ledger-tool/src/args.rs

@@ -5,7 +5,6 @@ use {
         accounts_db::{AccountsDb, AccountsDbConfig, CreateAncientStorage},
         accounts_file::StorageAccess,
         accounts_index::{AccountsIndexConfig, IndexLimitMb, ScanFilter},
-        partitioned_rewards::TestPartitionedEpochRewards,
         utils::create_and_canonicalize_directories,
     },
     solana_clap_utils::{
@@ -301,15 +300,6 @@ pub fn get_accounts_db_config(
         ..AccountsIndexConfig::default()
     };
 
-    let test_partitioned_epoch_rewards =
-        if arg_matches.is_present("partitioned_epoch_rewards_compare_calculation") {
-            TestPartitionedEpochRewards::CompareResults
-        } else if arg_matches.is_present("partitioned_epoch_rewards_force_enable_single_slot") {
-            TestPartitionedEpochRewards::ForcePartitionedEpochRewardsInOneBlock
-        } else {
-            TestPartitionedEpochRewards::None
-        };
-
     let accounts_hash_cache_path = arg_matches
         .value_of("accounts_hash_cache_path")
         .map(Into::into)
@@ -388,7 +378,6 @@ pub fn get_accounts_db_config(
         .ok(),
         exhaustively_verify_refcounts: arg_matches.is_present("accounts_db_verify_refcounts"),
         skip_initial_hash_calc: arg_matches.is_present("accounts_db_skip_initial_hash_calculation"),
-        test_partitioned_epoch_rewards,
         test_skip_rewrites_but_include_in_bank_hash: arg_matches
             .is_present("accounts_db_test_skip_rewrites"),
         create_ancient_storage,

+ 0 - 23
ledger-tool/src/main.rs

@@ -1136,29 +1136,6 @@ fn main() {
                              tasks and assert.",
                         ),
                 )
-                .arg(
-                    Arg::with_name("partitioned_epoch_rewards_compare_calculation")
-                        .long("partitioned-epoch-rewards-compare-calculation")
-                        .takes_value(false)
-                        .help(
-                            "Do normal epoch rewards distribution, but also calculate rewards \
-                             using the partitioned rewards code path and compare the resulting \
-                             vote and stake accounts",
-                        )
-                        .hidden(hidden_unless_forced()),
-                )
-                .arg(
-                    Arg::with_name("partitioned_epoch_rewards_force_enable_single_slot")
-                        .long("partitioned-epoch-rewards-force-enable-single-slot")
-                        .takes_value(false)
-                        .help(
-                            "Force the partitioned rewards distribution, but distribute all \
-                             rewards in the first slot in the epoch. This should match consensus \
-                             with the normal rewards distribution.",
-                        )
-                        .conflicts_with("partitioned_epoch_rewards_compare_calculation")
-                        .hidden(hidden_unless_forced()),
-                )
                 .arg(
                     Arg::with_name("print_accounts_stats")
                         .long("print-accounts-stats")

+ 4 - 9
programs/bpf_loader/src/syscalls/mod.rs

@@ -23,11 +23,11 @@ use {
         bpf_account_data_direct_mapping, curve25519_syscall_enabled,
         disable_deploy_of_alloc_free_syscall, disable_fees_sysvar, disable_sbpf_v0_execution,
         enable_alt_bn128_compression_syscall, enable_alt_bn128_syscall, enable_big_mod_exp_syscall,
-        enable_get_epoch_stake_syscall, enable_partitioned_epoch_reward, enable_poseidon_syscall,
+        enable_get_epoch_stake_syscall, enable_poseidon_syscall,
         enable_sbpf_v1_deployment_and_execution, enable_sbpf_v2_deployment_and_execution,
         enable_sbpf_v3_deployment_and_execution, get_sysvar_syscall_enabled,
-        last_restart_slot_sysvar, partitioned_epoch_rewards_superfeature,
-        reenable_sbpf_v0_execution, remaining_compute_units_syscall_enabled, FeatureSet,
+        last_restart_slot_sysvar, reenable_sbpf_v0_execution,
+        remaining_compute_units_syscall_enabled, FeatureSet,
     },
     solana_log_collector::{ic_logger_msg, ic_msg},
     solana_poseidon as poseidon,
@@ -277,9 +277,6 @@ pub fn create_program_runtime_environment_v1<'a>(
     let blake3_syscall_enabled = feature_set.is_active(&blake3_syscall_enabled::id());
     let curve25519_syscall_enabled = feature_set.is_active(&curve25519_syscall_enabled::id());
     let disable_fees_sysvar = feature_set.is_active(&disable_fees_sysvar::id());
-    let epoch_rewards_syscall_enabled = feature_set
-        .is_active(&enable_partitioned_epoch_reward::id())
-        || feature_set.is_active(&partitioned_epoch_rewards_superfeature::id());
     let disable_deploy_of_alloc_free_syscall = reject_deployment_of_broken_elfs
         && feature_set.is_active(&disable_deploy_of_alloc_free_syscall::id());
     let last_restart_slot_syscall_enabled = feature_set.is_active(&last_restart_slot_sysvar::id());
@@ -416,9 +413,7 @@ pub fn create_program_runtime_environment_v1<'a>(
         SyscallGetLastRestartSlotSysvar::vm,
     )?;
 
-    register_feature_gated_function!(
-        result,
-        epoch_rewards_syscall_enabled,
+    result.register_function(
         "sol_get_epoch_rewards_sysvar",
         39,
         SyscallGetEpochRewardsSysvar::vm,

+ 14 - 528
runtime/src/bank.rs

@@ -48,12 +48,11 @@ use {
         serde_snapshot::BankIncrementalSnapshotPersistence,
         snapshot_hash::SnapshotHash,
         stake_account::StakeAccount,
-        stake_history::StakeHistory,
         stake_weighted_timestamp::{
             calculate_stake_weighted_timestamp, MaxAllowableDrift,
             MAX_ALLOWABLE_DRIFT_PERCENTAGE_FAST, MAX_ALLOWABLE_DRIFT_PERCENTAGE_SLOW_V2,
         },
-        stakes::{InvalidCacheEntryReason, Stakes, StakesCache, StakesEnum},
+        stakes::{Stakes, StakesCache, StakesEnum},
         status_cache::{SlotDelta, StatusCache},
         transaction_batch::{OwnedOrBorrowed, TransactionBatch},
         verify_precompiles::verify_precompiles,
@@ -65,8 +64,7 @@ use {
     log::*,
     rayon::{
         iter::{IntoParallelIterator, IntoParallelRefIterator, ParallelIterator},
-        slice::ParallelSlice,
-        ThreadPool, ThreadPoolBuilder,
+        ThreadPoolBuilder,
     },
     serde::Serialize,
     solana_accounts_db::{
@@ -88,7 +86,6 @@ use {
         blockhash_queue::BlockhashQueue,
         epoch_accounts_hash::EpochAccountsHash,
         sorted_storages::SortedStorages,
-        stake_rewards::StakeReward,
         storable_accounts::StorableAccounts,
     },
     solana_bpf_loader_program::syscalls::{
@@ -157,10 +154,7 @@ use {
         },
         transaction_context::{TransactionAccount, TransactionReturnData},
     },
-    solana_stake_program::{
-        points::{InflationPointCalculationEvent, PointValue},
-        stake_state::StakeStateV2,
-    },
+    solana_stake_program::points::InflationPointCalculationEvent,
     solana_svm::{
         account_loader::{collect_rent_from_account, LoadedTransaction},
         account_overrides::AccountOverrides,
@@ -182,7 +176,6 @@ use {
     solana_svm_transaction::svm_message::SVMMessage,
     solana_timings::{ExecuteTimingType, ExecuteTimings},
     solana_vote::vote_account::{VoteAccount, VoteAccountsHashMap},
-    solana_vote_program::vote_state::VoteState,
     std::{
         collections::{HashMap, HashSet},
         convert::TryFrom,
@@ -954,22 +947,6 @@ pub struct Bank {
     bank_hash_stats: AtomicBankHashStats,
 }
 
-struct VoteWithStakeDelegations {
-    vote_state: Arc<VoteState>,
-    vote_account: AccountSharedData,
-    delegations: Vec<(Pubkey, StakeAccount<Delegation>)>,
-}
-
-type VoteWithStakeDelegationsMap = DashMap<Pubkey, VoteWithStakeDelegations>;
-
-type InvalidCacheKeyMap = DashMap<Pubkey, InvalidCacheEntryReason>;
-
-struct LoadVoteAndStakeAccountsResult {
-    vote_with_stake_delegations_map: VoteWithStakeDelegationsMap,
-    invalid_vote_keys: InvalidCacheKeyMap,
-    vote_accounts_cache_miss_count: usize,
-}
-
 #[derive(Debug)]
 struct VoteReward {
     vote_account: AccountSharedData,
@@ -1449,9 +1426,7 @@ impl Bank {
                 let leader_schedule_epoch = new.epoch_schedule().get_leader_schedule_epoch(slot);
                 new.update_epoch_stakes(leader_schedule_epoch);
             }
-            if new.is_partitioned_rewards_code_enabled() {
-                new.distribute_partitioned_epoch_rewards();
-            }
+            new.distribute_partitioned_epoch_rewards();
         });
 
         let (_epoch, slot_index) = new.epoch_schedule.get_epoch_and_slot_index(new.slot);
@@ -1617,24 +1592,15 @@ impl Bank {
 
         let mut rewards_metrics = RewardsMetrics::default();
         // After saving a snapshot of stakes, apply stake rewards and commission
-        let (_, update_rewards_with_thread_pool_time_us) =
-            measure_us!(if self.is_partitioned_rewards_code_enabled() {
-                self.begin_partitioned_rewards(
-                    reward_calc_tracer,
-                    &thread_pool,
-                    parent_epoch,
-                    parent_slot,
-                    parent_height,
-                    &mut rewards_metrics,
-                );
-            } else {
-                self.update_rewards_with_thread_pool(
-                    parent_epoch,
-                    reward_calc_tracer,
-                    &thread_pool,
-                    &mut rewards_metrics,
-                )
-            });
+        let (_, update_rewards_with_thread_pool_time_us) = measure_us!(self
+            .begin_partitioned_rewards(
+                reward_calc_tracer,
+                &thread_pool,
+                parent_epoch,
+                parent_slot,
+                parent_height,
+                &mut rewards_metrics,
+            ));
 
         report_new_epoch_metrics(
             epoch,
@@ -2417,93 +2383,6 @@ impl Bank {
         );
     }
 
-    // update rewards based on the previous epoch
-    fn update_rewards_with_thread_pool(
-        &mut self,
-        prev_epoch: Epoch,
-        reward_calc_tracer: Option<impl Fn(&RewardCalculationEvent) + Send + Sync>,
-        thread_pool: &ThreadPool,
-        metrics: &mut RewardsMetrics,
-    ) {
-        let capitalization = self.capitalization();
-        let PrevEpochInflationRewards {
-            validator_rewards,
-            prev_epoch_duration_in_years,
-            validator_rate,
-            foundation_rate,
-        } = self.calculate_previous_epoch_inflation_rewards(capitalization, prev_epoch);
-
-        let old_vote_balance_and_staked = self.stakes_cache.stakes().vote_balance_and_staked();
-
-        self.pay_validator_rewards_with_thread_pool(
-            prev_epoch,
-            validator_rewards,
-            reward_calc_tracer,
-            thread_pool,
-            metrics,
-        );
-
-        let new_vote_balance_and_staked = self.stakes_cache.stakes().vote_balance_and_staked();
-        let validator_rewards_paid = new_vote_balance_and_staked - old_vote_balance_and_staked;
-        assert_eq!(
-            validator_rewards_paid,
-            u64::try_from(
-                self.rewards
-                    .read()
-                    .unwrap()
-                    .iter()
-                    .map(|(_address, reward_info)| {
-                        match reward_info.reward_type {
-                            RewardType::Voting | RewardType::Staking => reward_info.lamports,
-                            _ => 0,
-                        }
-                    })
-                    .sum::<i64>()
-            )
-            .unwrap()
-        );
-
-        // verify that we didn't pay any more than we expected to
-        assert!(validator_rewards >= validator_rewards_paid);
-
-        info!(
-            "distributed inflation: {} (rounded from: {})",
-            validator_rewards_paid, validator_rewards
-        );
-        let (num_stake_accounts, num_vote_accounts) = {
-            let stakes = self.stakes_cache.stakes();
-            (
-                stakes.stake_delegations().len(),
-                stakes.vote_accounts().len(),
-            )
-        };
-        self.capitalization
-            .fetch_add(validator_rewards_paid, Relaxed);
-
-        let active_stake = if let Some(stake_history_entry) =
-            self.stakes_cache.stakes().history().get(prev_epoch)
-        {
-            stake_history_entry.effective
-        } else {
-            0
-        };
-
-        datapoint_warn!(
-            "epoch_rewards",
-            ("slot", self.slot, i64),
-            ("epoch", prev_epoch, i64),
-            ("validator_rate", validator_rate, f64),
-            ("foundation_rate", foundation_rate, f64),
-            ("epoch_duration_in_years", prev_epoch_duration_in_years, f64),
-            ("validator_rewards", validator_rewards_paid, i64),
-            ("active_stake", active_stake, i64),
-            ("pre_capitalization", capitalization, i64),
-            ("post_capitalization", self.capitalization(), i64),
-            ("num_stake_accounts", num_stake_accounts, i64),
-            ("num_vote_accounts", num_vote_accounts, i64),
-        );
-    }
-
     fn filter_stake_delegations<'a>(
         &self,
         stakes: &'a Stakes<StakeAccount<Delegation>>,
@@ -2537,396 +2416,6 @@ impl Bank {
         }
     }
 
-    fn _load_vote_and_stake_accounts(
-        &self,
-        thread_pool: &ThreadPool,
-        reward_calc_tracer: Option<impl RewardCalcTracer>,
-    ) -> LoadVoteAndStakeAccountsResult {
-        let stakes = self.stakes_cache.stakes();
-        let stake_delegations = self.filter_stake_delegations(&stakes);
-
-        // Obtain all unique voter pubkeys from stake delegations.
-        fn merge(mut acc: HashSet<Pubkey>, other: HashSet<Pubkey>) -> HashSet<Pubkey> {
-            if acc.len() < other.len() {
-                return merge(other, acc);
-            }
-            acc.extend(other);
-            acc
-        }
-        let voter_pubkeys = thread_pool.install(|| {
-            stake_delegations
-                .par_iter()
-                .fold(
-                    HashSet::default,
-                    |mut voter_pubkeys, (_stake_pubkey, stake_account)| {
-                        voter_pubkeys.insert(stake_account.delegation().voter_pubkey);
-                        voter_pubkeys
-                    },
-                )
-                .reduce(HashSet::default, merge)
-        });
-        // Obtain vote-accounts for unique voter pubkeys.
-        let cached_vote_accounts = stakes.vote_accounts();
-        let solana_vote_program: Pubkey = solana_vote_program::id();
-        let vote_accounts_cache_miss_count = AtomicUsize::default();
-        let get_vote_account = |vote_pubkey: &Pubkey| -> Option<VoteAccount> {
-            if let Some(vote_account) = cached_vote_accounts.get(vote_pubkey) {
-                return Some(vote_account.clone());
-            }
-            // If accounts-db contains a valid vote account, then it should
-            // already have been cached in cached_vote_accounts; so the code
-            // below is only for sanity check, and can be removed once
-            // vote_accounts_cache_miss_count is shown to be always zero.
-            let account = self.get_account_with_fixed_root(vote_pubkey)?;
-            if account.owner() == &solana_vote_program
-                && VoteState::deserialize(account.data()).is_ok()
-            {
-                vote_accounts_cache_miss_count.fetch_add(1, Relaxed);
-            }
-            VoteAccount::try_from(account).ok()
-        };
-        let invalid_vote_keys = DashMap::<Pubkey, InvalidCacheEntryReason>::new();
-        let make_vote_delegations_entry = |vote_pubkey| {
-            let Some(vote_account) = get_vote_account(&vote_pubkey) else {
-                invalid_vote_keys.insert(vote_pubkey, InvalidCacheEntryReason::Missing);
-                return None;
-            };
-            if vote_account.owner() != &solana_vote_program {
-                invalid_vote_keys.insert(vote_pubkey, InvalidCacheEntryReason::WrongOwner);
-                return None;
-            }
-            let vote_with_stake_delegations = VoteWithStakeDelegations {
-                vote_state: Arc::new(vote_account.vote_state().clone()),
-                vote_account: AccountSharedData::from(vote_account),
-                delegations: Vec::default(),
-            };
-            Some((vote_pubkey, vote_with_stake_delegations))
-        };
-        let vote_with_stake_delegations_map: DashMap<Pubkey, VoteWithStakeDelegations> =
-            thread_pool.install(|| {
-                voter_pubkeys
-                    .into_par_iter()
-                    .filter_map(make_vote_delegations_entry)
-                    .collect()
-            });
-        // Join stake accounts with vote-accounts.
-        let push_stake_delegation = |(stake_pubkey, stake_account): (&Pubkey, &StakeAccount<_>)| {
-            let delegation = stake_account.delegation();
-            let Some(mut vote_delegations) =
-                vote_with_stake_delegations_map.get_mut(&delegation.voter_pubkey)
-            else {
-                return;
-            };
-            if let Some(reward_calc_tracer) = reward_calc_tracer.as_ref() {
-                let delegation =
-                    InflationPointCalculationEvent::Delegation(*delegation, solana_vote_program);
-                let event = RewardCalculationEvent::Staking(stake_pubkey, &delegation);
-                reward_calc_tracer(&event);
-            }
-            let stake_delegation = (*stake_pubkey, stake_account.clone());
-            vote_delegations.delegations.push(stake_delegation);
-        };
-        thread_pool.install(|| {
-            stake_delegations
-                .into_par_iter()
-                .for_each(push_stake_delegation);
-        });
-        LoadVoteAndStakeAccountsResult {
-            vote_with_stake_delegations_map,
-            invalid_vote_keys,
-            vote_accounts_cache_miss_count: vote_accounts_cache_miss_count.into_inner(),
-        }
-    }
-
-    /// Load, calculate and payout epoch rewards for stake and vote accounts
-    fn pay_validator_rewards_with_thread_pool(
-        &mut self,
-        rewarded_epoch: Epoch,
-        rewards: u64,
-        reward_calc_tracer: Option<impl RewardCalcTracer>,
-        thread_pool: &ThreadPool,
-        metrics: &mut RewardsMetrics,
-    ) {
-        let stake_history = self.stakes_cache.stakes().history().clone();
-        let vote_with_stake_delegations_map =
-            self.load_vote_and_stake_accounts(thread_pool, reward_calc_tracer.as_ref(), metrics);
-
-        let point_value = self.calculate_reward_points(
-            &vote_with_stake_delegations_map,
-            rewards,
-            &stake_history,
-            thread_pool,
-            metrics,
-        );
-
-        if let Some(point_value) = point_value {
-            let (vote_account_rewards, stake_rewards) = self.redeem_rewards(
-                vote_with_stake_delegations_map,
-                rewarded_epoch,
-                point_value,
-                &stake_history,
-                thread_pool,
-                reward_calc_tracer.as_ref(),
-                metrics,
-            );
-
-            // this checking of an unactivated feature can be enabled in tests or with a validator by passing `--partitioned-epoch-rewards-compare-calculation`
-            if self
-                .partitioned_epoch_rewards_config()
-                .test_compare_partitioned_epoch_rewards
-            {
-                // immutable `&self` to avoid side effects
-                (self as &Bank).compare_with_partitioned_rewards(
-                    &stake_rewards,
-                    &vote_account_rewards,
-                    rewarded_epoch,
-                    thread_pool,
-                    null_tracer(),
-                );
-            }
-
-            self.store_stake_accounts(thread_pool, &stake_rewards, metrics);
-            let vote_rewards = self.store_vote_accounts(vote_account_rewards, metrics);
-            self.update_reward_history(stake_rewards, vote_rewards);
-        }
-    }
-
-    fn load_vote_and_stake_accounts(
-        &mut self,
-        thread_pool: &ThreadPool,
-        reward_calc_tracer: Option<impl RewardCalcTracer>,
-        metrics: &mut RewardsMetrics,
-    ) -> VoteWithStakeDelegationsMap {
-        let (
-            LoadVoteAndStakeAccountsResult {
-                vote_with_stake_delegations_map,
-                invalid_vote_keys,
-                vote_accounts_cache_miss_count,
-            },
-            load_vote_and_stake_accounts_us,
-        ) = measure_us!({
-            self._load_vote_and_stake_accounts(thread_pool, reward_calc_tracer.as_ref())
-        });
-        metrics
-            .load_vote_and_stake_accounts_us
-            .fetch_add(load_vote_and_stake_accounts_us, Relaxed);
-        metrics.vote_accounts_cache_miss_count += vote_accounts_cache_miss_count;
-        self.stakes_cache
-            .handle_invalid_keys(invalid_vote_keys, self.slot());
-        vote_with_stake_delegations_map
-    }
-
-    fn calculate_reward_points(
-        &self,
-        vote_with_stake_delegations_map: &VoteWithStakeDelegationsMap,
-        rewards: u64,
-        stake_history: &StakeHistory,
-        thread_pool: &ThreadPool,
-        metrics: &RewardsMetrics,
-    ) -> Option<PointValue> {
-        let new_warmup_cooldown_rate_epoch = self.new_warmup_cooldown_rate_epoch();
-        let (points, calculate_points_us) = measure_us!(thread_pool.install(|| {
-            vote_with_stake_delegations_map
-                .par_iter()
-                .map(|entry| {
-                    let VoteWithStakeDelegations {
-                        vote_state,
-                        delegations,
-                        ..
-                    } = entry.value();
-
-                    delegations
-                        .par_iter()
-                        .map(|(_stake_pubkey, stake_account)| {
-                            solana_stake_program::points::calculate_points(
-                                stake_account.stake_state(),
-                                vote_state,
-                                stake_history,
-                                new_warmup_cooldown_rate_epoch,
-                            )
-                            .unwrap_or(0)
-                        })
-                        .sum::<u128>()
-                })
-                .sum()
-        }));
-        metrics
-            .calculate_points_us
-            .fetch_add(calculate_points_us, Relaxed);
-
-        (points > 0).then_some(PointValue { rewards, points })
-    }
-
-    fn redeem_rewards(
-        &self,
-        vote_with_stake_delegations_map: DashMap<Pubkey, VoteWithStakeDelegations>,
-        rewarded_epoch: Epoch,
-        point_value: PointValue,
-        stake_history: &StakeHistory,
-        thread_pool: &ThreadPool,
-        reward_calc_tracer: Option<impl RewardCalcTracer>,
-        metrics: &mut RewardsMetrics,
-    ) -> (VoteRewards, StakeRewards) {
-        let new_warmup_cooldown_rate_epoch = self.new_warmup_cooldown_rate_epoch();
-        let vote_account_rewards: VoteRewards =
-            DashMap::with_capacity(vote_with_stake_delegations_map.len());
-        let stake_delegation_iterator = vote_with_stake_delegations_map.into_par_iter().flat_map(
-            |(
-                vote_pubkey,
-                VoteWithStakeDelegations {
-                    vote_state,
-                    vote_account,
-                    delegations,
-                },
-            )| {
-                vote_account_rewards.insert(
-                    vote_pubkey,
-                    VoteReward {
-                        vote_account,
-                        commission: vote_state.commission,
-                        vote_rewards: 0,
-                        vote_needs_store: false,
-                    },
-                );
-                delegations
-                    .into_par_iter()
-                    .map(move |delegation| (vote_pubkey, Arc::clone(&vote_state), delegation))
-            },
-        );
-
-        let (stake_rewards, redeem_rewards_us) = measure_us!(thread_pool.install(|| {
-            stake_delegation_iterator
-                .filter_map(|(vote_pubkey, vote_state, (stake_pubkey, stake_account))| {
-                    // curry closure to add the contextual stake_pubkey
-                    let reward_calc_tracer = reward_calc_tracer.as_ref().map(|outer| {
-                        // inner
-                        move |inner_event: &_| {
-                            outer(&RewardCalculationEvent::Staking(&stake_pubkey, inner_event))
-                        }
-                    });
-                    let (mut stake_account, stake_state) =
-                        <(AccountSharedData, StakeStateV2)>::from(stake_account);
-                    let redeemed = solana_stake_program::rewards::redeem_rewards(
-                        rewarded_epoch,
-                        stake_state,
-                        &mut stake_account,
-                        &vote_state,
-                        &point_value,
-                        stake_history,
-                        reward_calc_tracer.as_ref(),
-                        new_warmup_cooldown_rate_epoch,
-                    );
-                    if let Ok((stakers_reward, voters_reward)) = redeemed {
-                        // track voter rewards
-                        if let Some(VoteReward {
-                            vote_account: _,
-                            commission: _,
-                            vote_rewards: vote_rewards_sum,
-                            vote_needs_store,
-                        }) = vote_account_rewards.get_mut(&vote_pubkey).as_deref_mut()
-                        {
-                            *vote_needs_store = true;
-                            *vote_rewards_sum = vote_rewards_sum.saturating_add(voters_reward);
-                        }
-
-                        let post_balance = stake_account.lamports();
-                        return Some(StakeReward {
-                            stake_pubkey,
-                            stake_reward_info: RewardInfo {
-                                reward_type: RewardType::Staking,
-                                lamports: i64::try_from(stakers_reward).unwrap(),
-                                post_balance,
-                                commission: Some(vote_state.commission),
-                            },
-                            stake_account,
-                        });
-                    } else {
-                        debug!(
-                            "solana_stake_program::rewards::redeem_rewards() failed for {}: {:?}",
-                            stake_pubkey, redeemed
-                        );
-                    }
-                    None
-                })
-                .collect()
-        }));
-        metrics.redeem_rewards_us += redeem_rewards_us;
-        (vote_account_rewards, stake_rewards)
-    }
-
-    fn store_stake_accounts(
-        &self,
-        thread_pool: &ThreadPool,
-        stake_rewards: &[StakeReward],
-        metrics: &RewardsMetrics,
-    ) {
-        // store stake account even if stake_reward is 0
-        // because credits observed has changed
-        let now = Instant::now();
-        let slot = self.slot();
-        self.stakes_cache.update_stake_accounts(
-            thread_pool,
-            stake_rewards,
-            self.new_warmup_cooldown_rate_epoch(),
-        );
-        assert!(!self.freeze_started());
-        thread_pool.install(|| {
-            stake_rewards.par_chunks(512).for_each(|chunk| {
-                let to_store = (slot, chunk);
-                self.update_bank_hash_stats(&to_store);
-                self.rc.accounts.store_accounts_cached(to_store);
-            })
-        });
-        metrics
-            .store_stake_accounts_us
-            .fetch_add(now.elapsed().as_micros() as u64, Relaxed);
-    }
-
-    fn store_vote_accounts(
-        &self,
-        vote_account_rewards: VoteRewards,
-        metrics: &RewardsMetrics,
-    ) -> Vec<(Pubkey, RewardInfo)> {
-        let (vote_rewards, store_vote_accounts_us) = measure_us!(vote_account_rewards
-            .into_iter()
-            .filter_map(
-                |(
-                    vote_pubkey,
-                    VoteReward {
-                        mut vote_account,
-                        commission,
-                        vote_rewards,
-                        vote_needs_store,
-                    },
-                )| {
-                    if let Err(err) = vote_account.checked_add_lamports(vote_rewards) {
-                        debug!("reward redemption failed for {}: {:?}", vote_pubkey, err);
-                        return None;
-                    }
-
-                    if vote_needs_store {
-                        self.store_account(&vote_pubkey, &vote_account);
-                    }
-
-                    Some((
-                        vote_pubkey,
-                        RewardInfo {
-                            reward_type: RewardType::Voting,
-                            lamports: vote_rewards as i64,
-                            post_balance: vote_account.lamports(),
-                            commission: Some(commission),
-                        },
-                    ))
-                },
-            )
-            .collect::<Vec<_>>());
-
-        metrics
-            .store_vote_accounts_us
-            .fetch_add(store_vote_accounts_us, Relaxed);
-        vote_rewards
-    }
-
     /// return reward info for each vote account
     /// return account data for each vote account that needs to be stored
     /// This return value is a little awkward at the moment so that downstream existing code in the non-partitioned rewards code path can be re-used without duplication or modification.
@@ -5673,16 +5162,13 @@ impl Bank {
         let measure_total = Measure::start("");
 
         let slot = self.slot();
-        let ignore = (!self.is_partitioned_rewards_feature_enabled()
-            && self.force_partition_rewards_in_first_block_of_epoch())
-        .then_some(sysvar::epoch_rewards::id());
         let (accounts_delta_hash, accounts_delta_hash_us) = measure_us!({
             self.rc
                 .accounts
                 .accounts_db
                 .calculate_accounts_delta_hash_internal(
                     slot,
-                    ignore,
+                    None,
                     self.skipped_rewrites.lock().unwrap().clone(),
                 )
         });

+ 1 - 9
runtime/src/bank/partitioned_epoch_rewards/calculation.rs

@@ -48,7 +48,6 @@ impl Bank {
         rewards_metrics: &mut RewardsMetrics,
     ) {
         let CalculateRewardsAndDistributeVoteRewardsResult {
-            total_rewards,
             distributed_rewards,
             point_value,
             stake_rewards_by_partition,
@@ -61,12 +60,7 @@ impl Bank {
 
         let slot = self.slot();
         let distribution_starting_block_height =
-            // For live-cluster testing pre-activation
-            if self.force_partition_rewards_in_first_block_of_epoch() {
-                self.block_height()
-            } else {
-                self.block_height() + REWARD_CALCULATION_NUM_BLOCKS
-            };
+            self.block_height() + REWARD_CALCULATION_NUM_BLOCKS;
 
         let num_partitions = stake_rewards_by_partition.len() as u64;
 
@@ -76,7 +70,6 @@ impl Bank {
         );
 
         self.create_epoch_rewards_sysvar(
-            total_rewards,
             distributed_rewards,
             distribution_starting_block_height,
             num_partitions,
@@ -176,7 +169,6 @@ impl Bank {
         );
 
         CalculateRewardsAndDistributeVoteRewardsResult {
-            total_rewards: validator_rewards_paid + total_stake_rewards_lamports,
             distributed_rewards: validator_rewards_paid,
             point_value,
             stake_rewards_by_partition,

+ 0 - 114
runtime/src/bank/partitioned_epoch_rewards/compare.rs

@@ -1,114 +0,0 @@
-use {
-    super::{Bank, PartitionedRewardsCalculation, PartitionedStakeReward},
-    crate::bank::{RewardCalcTracer, RewardsMetrics, VoteReward},
-    dashmap::DashMap,
-    log::info,
-    rayon::ThreadPool,
-    solana_accounts_db::stake_rewards::StakeReward,
-    solana_sdk::{
-        account::{AccountSharedData, WritableAccount},
-        clock::Epoch,
-        pubkey::Pubkey,
-        reward_info::RewardInfo,
-    },
-    std::collections::HashMap,
-};
-
-impl Bank {
-    /// compare the vote and stake accounts between the normal rewards calculation code
-    /// and the partitioned rewards calculation code
-    /// `stake_rewards_expected` and `vote_rewards_expected` are the results of the normal rewards calculation code
-    /// This fn should have NO side effects.
-    pub(in crate::bank) fn compare_with_partitioned_rewards(
-        &self,
-        stake_rewards_expected: &[StakeReward],
-        vote_rewards_expected: &DashMap<Pubkey, VoteReward>,
-        rewarded_epoch: Epoch,
-        thread_pool: &ThreadPool,
-        reward_calc_tracer: Option<impl RewardCalcTracer>,
-    ) {
-        let partitioned_rewards = self.calculate_rewards_for_partitioning(
-            rewarded_epoch,
-            reward_calc_tracer,
-            thread_pool,
-            &mut RewardsMetrics::default(),
-        );
-        Self::compare_with_partitioned_rewards_results(
-            stake_rewards_expected,
-            vote_rewards_expected,
-            partitioned_rewards,
-        );
-    }
-
-    /// compare the vote and stake accounts between the normal rewards calculation code
-    /// and the partitioned rewards calculation code
-    /// `stake_rewards_expected` and `vote_rewards_expected` are the results of the normal rewards calculation code
-    /// This fn should have NO side effects.
-    /// This fn is only called in tests or with a debug cli arg prior to partitioned rewards feature activation.
-    fn compare_with_partitioned_rewards_results(
-        stake_rewards_expected: &[StakeReward],
-        vote_rewards_expected: &DashMap<Pubkey, VoteReward>,
-        partitioned_rewards: PartitionedRewardsCalculation,
-    ) {
-        // put partitioned stake rewards in a hashmap
-        let mut stake_rewards: HashMap<Pubkey, &PartitionedStakeReward> = HashMap::default();
-        partitioned_rewards
-            .stake_rewards_by_partition
-            .stake_rewards_by_partition
-            .iter()
-            .flatten()
-            .for_each(|stake_reward| {
-                stake_rewards.insert(stake_reward.stake_pubkey, stake_reward);
-            });
-
-        // verify stake rewards match expected
-        stake_rewards_expected.iter().for_each(|stake_reward| {
-            let partitioned = stake_rewards.remove(&stake_reward.stake_pubkey).unwrap();
-            let converted = PartitionedStakeReward::maybe_from(stake_reward).expect(
-                "StakeRewards should only be deserializable accounts with state \
-                 StakeStateV2::Stake",
-            );
-            assert_eq!(partitioned, &converted);
-        });
-        assert!(stake_rewards.is_empty(), "{stake_rewards:?}");
-
-        let mut vote_rewards: HashMap<Pubkey, (RewardInfo, AccountSharedData)> = HashMap::default();
-        partitioned_rewards
-            .vote_account_rewards
-            .accounts_to_store
-            .iter()
-            .enumerate()
-            .for_each(|(i, account)| {
-                if let Some(account) = account {
-                    let reward = &partitioned_rewards.vote_account_rewards.rewards[i];
-                    vote_rewards.insert(reward.0, (reward.1, account.clone()));
-                }
-            });
-
-        // verify vote rewards match expected
-        vote_rewards_expected.iter().for_each(|entry| {
-            if entry.value().vote_needs_store {
-                let partitioned = vote_rewards.remove(entry.key()).unwrap();
-                let mut to_store_partitioned = partitioned.1.clone();
-                to_store_partitioned.set_lamports(partitioned.0.post_balance);
-                let mut to_store_normal = entry.value().vote_account.clone();
-                _ = to_store_normal.checked_add_lamports(entry.value().vote_rewards);
-                assert_eq!(to_store_partitioned, to_store_normal, "{:?}", entry.key());
-            }
-        });
-        assert!(vote_rewards.is_empty(), "{vote_rewards:?}");
-        info!(
-            "verified partitioned rewards calculation matching: {}, {}",
-            partitioned_rewards
-                .stake_rewards_by_partition
-                .stake_rewards_by_partition
-                .iter()
-                .map(|rewards| rewards.len())
-                .sum::<usize>(),
-            partitioned_rewards
-                .vote_account_rewards
-                .accounts_to_store
-                .len()
-        );
-    }
-}

+ 1 - 3
runtime/src/bank/partitioned_epoch_rewards/distribution.rs

@@ -348,15 +348,13 @@ mod tests {
         let (mut genesis_config, _mint_keypair) =
             create_genesis_config(1_000_000 * LAMPORTS_PER_SOL);
         genesis_config.epoch_schedule = EpochSchedule::custom(432000, 432000, false);
-        let mut bank = Bank::new_for_tests(&genesis_config);
-        bank.activate_feature(&solana_feature_set::partitioned_epoch_rewards_superfeature::id());
+        let bank = Bank::new_for_tests(&genesis_config);
 
         // Set up epoch_rewards sysvar with rewards with 1e9 lamports to distribute.
         let total_rewards = 1_000_000_000;
         let num_partitions = 2; // num_partitions is arbitrary and unimportant for this test
         let total_points = (total_rewards * 42) as u128; // total_points is arbitrary for the purposes of this test
         bank.create_epoch_rewards_sysvar(
-            total_rewards,
             0,
             42,
             num_partitions,

+ 22 - 186
runtime/src/bank/partitioned_epoch_rewards/mod.rs

@@ -1,5 +1,4 @@
 mod calculation;
-mod compare;
 mod distribution;
 mod epoch_rewards_hasher;
 mod sysvar;
@@ -10,13 +9,11 @@ use {
     solana_accounts_db::{
         partitioned_rewards::PartitionedEpochRewardsConfig, stake_rewards::StakeReward,
     },
-    solana_feature_set as feature_set,
     solana_sdk::{
         account::AccountSharedData,
-        account_utils::StateMut,
         pubkey::Pubkey,
         reward_info::RewardInfo,
-        stake::state::{Delegation, Stake, StakeStateV2},
+        stake::state::{Delegation, Stake},
     },
     solana_stake_program::points::PointValue,
     solana_vote::vote_account::VoteAccounts,
@@ -39,20 +36,6 @@ pub(crate) struct PartitionedStakeReward {
     pub stake_reward_info: RewardInfo,
 }
 
-impl PartitionedStakeReward {
-    fn maybe_from(stake_reward: &StakeReward) -> Option<Self> {
-        if let Ok(StakeStateV2::Stake(_meta, stake, _flags)) = stake_reward.stake_account.state() {
-            Some(Self {
-                stake_pubkey: stake_reward.stake_pubkey,
-                stake,
-                stake_reward_info: stake_reward.stake_reward_info,
-            })
-        } else {
-            None
-        }
-    }
-}
-
 type PartitionedStakeRewards = Vec<PartitionedStakeReward>;
 
 #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
@@ -146,9 +129,6 @@ pub(super) struct StakeRewardCalculationPartitioned {
 }
 
 pub(super) struct CalculateRewardsAndDistributeVoteRewardsResult {
-    /// total rewards to be distributed in the epoch (including both vote
-    /// rewards and stake rewards)
-    pub(super) total_rewards: u64,
     /// distributed vote rewards
     pub(super) distributed_rewards: u64,
     /// total rewards and points calculated for the current epoch, where points
@@ -192,14 +172,6 @@ impl Bank {
         }
     }
 
-    pub(super) fn is_partitioned_rewards_feature_enabled(&self) -> bool {
-        self.feature_set
-            .is_active(&feature_set::enable_partitioned_epoch_reward::id())
-            || self
-                .feature_set
-                .is_active(&feature_set::partitioned_epoch_rewards_superfeature::id())
-    }
-
     pub(crate) fn set_epoch_reward_status_active(
         &mut self,
         distribution_starting_block_height: u64,
@@ -248,25 +220,10 @@ impl Bank {
         }
     }
 
-    /// true if it is ok to run partitioned rewards code.
-    /// This means the feature is activated or certain testing situations.
-    pub(super) fn is_partitioned_rewards_code_enabled(&self) -> bool {
-        self.is_partitioned_rewards_feature_enabled()
-            || self
-                .partitioned_epoch_rewards_config()
-                .test_enable_partitioned_rewards
-    }
-
     /// For testing only
     pub fn force_reward_interval_end_for_tests(&mut self) {
         self.epoch_reward_status = EpochRewardStatus::Inactive;
     }
-
-    pub(super) fn force_partition_rewards_in_first_block_of_epoch(&self) -> bool {
-        self.partitioned_epoch_rewards_config()
-            .test_enable_partitioned_rewards
-            && self.partitioned_rewards_stake_account_stores_per_block() == u64::MAX
-    }
 }
 
 #[cfg(test)]
@@ -281,18 +238,16 @@ mod tests {
             runtime_config::RuntimeConfig,
         },
         assert_matches::assert_matches,
-        solana_accounts_db::{
-            accounts_db::{AccountsDbConfig, ACCOUNTS_DB_CONFIG_FOR_TESTING},
-            partitioned_rewards::TestPartitionedEpochRewards,
-        },
+        solana_accounts_db::accounts_db::{AccountsDbConfig, ACCOUNTS_DB_CONFIG_FOR_TESTING},
         solana_sdk::{
             account::Account,
+            account_utils::StateMut,
             epoch_schedule::EpochSchedule,
             native_token::LAMPORTS_PER_SOL,
             reward_type::RewardType,
             signature::Signer,
             signer::keypair::Keypair,
-            stake::instruction::StakeError,
+            stake::{instruction::StakeError, state::StakeStateV2},
             system_transaction,
             transaction::Transaction,
             vote::state::{VoteStateVersions, MAX_LOCKOUT_HISTORY},
@@ -304,6 +259,20 @@ mod tests {
     };
 
     impl PartitionedStakeReward {
+        fn maybe_from(stake_reward: &StakeReward) -> Option<Self> {
+            if let Ok(StakeStateV2::Stake(_meta, stake, _flags)) =
+                stake_reward.stake_account.state()
+            {
+                Some(Self {
+                    stake_pubkey: stake_reward.stake_pubkey,
+                    stake,
+                    stake_reward_info: stake_reward.stake_reward_info,
+                })
+            } else {
+                None
+            }
+        }
+
         pub fn new_random() -> Self {
             Self::maybe_from(&StakeReward::new_random()).unwrap()
         }
@@ -384,10 +353,8 @@ mod tests {
         genesis_config.epoch_schedule = EpochSchedule::new(SLOTS_PER_EPOCH);
 
         let mut accounts_db_config: AccountsDbConfig = ACCOUNTS_DB_CONFIG_FOR_TESTING.clone();
-        accounts_db_config.test_partitioned_epoch_rewards =
-            TestPartitionedEpochRewards::PartitionedEpochRewardsConfigRewardBlocks {
-                stake_account_stores_per_block,
-            };
+        accounts_db_config.partitioned_epoch_rewards_config =
+            PartitionedEpochRewardsConfig::new_for_test(stake_account_stores_per_block);
 
         let bank = Bank::new_with_paths(
             &genesis_config,
@@ -471,16 +438,6 @@ mod tests {
         assert!(bank.get_reward_interval() == RewardInterval::OutsideInterval);
     }
 
-    #[test]
-    fn test_is_partitioned_reward_feature_enable() {
-        let (genesis_config, _mint_keypair) = create_genesis_config(1_000_000 * LAMPORTS_PER_SOL);
-
-        let mut bank = Bank::new_for_tests(&genesis_config);
-        assert!(!bank.is_partitioned_rewards_feature_enabled());
-        bank.activate_feature(&feature_set::partitioned_epoch_rewards_superfeature::id());
-        assert!(bank.is_partitioned_rewards_feature_enabled());
-    }
-
     /// Test get_reward_distribution_num_blocks during small epoch
     /// The num_credit_blocks should be cap to 10% of the total number of blocks in the epoch.
     #[test]
@@ -491,10 +448,8 @@ mod tests {
 
         // Config stake reward distribution to be 10 per block
         let mut accounts_db_config: AccountsDbConfig = ACCOUNTS_DB_CONFIG_FOR_TESTING.clone();
-        accounts_db_config.test_partitioned_epoch_rewards =
-            TestPartitionedEpochRewards::PartitionedEpochRewardsConfigRewardBlocks {
-                stake_account_stores_per_block: 10,
-            };
+        accounts_db_config.partitioned_epoch_rewards_config =
+            PartitionedEpochRewardsConfig::new_for_test(10);
 
         let bank = Bank::new_with_paths(
             &genesis_config,
@@ -862,7 +817,6 @@ mod tests {
         let RewardBank { bank, .. } =
             create_reward_bank(num_rewards, stake_account_stores_per_block, starting_slot);
 
-        assert!(bank.is_partitioned_rewards_feature_enabled());
         // Slot before the epoch boundary contains empty rewards (since fees are
         // off), and no partitions because not at the epoch boundary
         assert_eq!(
@@ -878,7 +832,6 @@ mod tests {
             &Pubkey::default(),
             SLOTS_PER_EPOCH,
         ));
-        assert!(epoch_boundary_bank.is_partitioned_rewards_feature_enabled());
         // Slot at the epoch boundary contains voting rewards only, as well as partition data
         let KeyedRewardsAndNumPartitions {
             keyed_rewards,
@@ -900,7 +853,6 @@ mod tests {
             &Pubkey::default(),
             SLOTS_PER_EPOCH + 1,
         ));
-        assert!(partition0_bank.is_partitioned_rewards_feature_enabled());
         // Slot after the epoch boundary contains first partition of staking
         // rewards, and no partitions because not at the epoch boundary
         let KeyedRewardsAndNumPartitions {
@@ -918,7 +870,6 @@ mod tests {
             &Pubkey::default(),
             SLOTS_PER_EPOCH + 2,
         ));
-        assert!(partition1_bank.is_partitioned_rewards_feature_enabled());
         // Slot 2 after the epoch boundary contains second partition of staking
         // rewards, and no partitions because not at the epoch boundary
         let KeyedRewardsAndNumPartitions {
@@ -935,7 +886,6 @@ mod tests {
         assert_eq!(total_staking_rewards, num_rewards);
 
         let bank = Bank::new_from_parent(partition1_bank, &Pubkey::default(), SLOTS_PER_EPOCH + 3);
-        assert!(bank.is_partitioned_rewards_feature_enabled());
         // Next slot contains empty rewards (since fees are off), and no
         // partitions because not at the epoch boundary
         assert_eq!(
@@ -947,120 +897,6 @@ mod tests {
         );
     }
 
-    #[test]
-    fn test_get_rewards_and_partitions_before_feature() {
-        let starting_slot = SLOTS_PER_EPOCH - 1;
-        let num_rewards = 100;
-
-        let validator_keypairs = (0..num_rewards)
-            .map(|_| ValidatorVoteKeypairs::new_rand())
-            .collect::<Vec<_>>();
-
-        let GenesisConfigInfo {
-            mut genesis_config, ..
-        } = create_genesis_config_with_vote_accounts(
-            1_000_000_000,
-            &validator_keypairs,
-            vec![2_000_000_000; num_rewards],
-        );
-        genesis_config.epoch_schedule = EpochSchedule::new(SLOTS_PER_EPOCH);
-
-        // Set feature to inactive
-        genesis_config
-            .accounts
-            .remove(&feature_set::enable_partitioned_epoch_reward::id());
-        genesis_config
-            .accounts
-            .remove(&feature_set::partitioned_epoch_rewards_superfeature::id());
-
-        let bank = Bank::new_for_tests(&genesis_config);
-
-        for validator_vote_keypairs in &validator_keypairs {
-            let vote_id = validator_vote_keypairs.vote_keypair.pubkey();
-            let mut vote_account = bank.get_account(&vote_id).unwrap();
-            // generate some rewards
-            let mut vote_state = Some(vote_state::from(&vote_account).unwrap());
-            for i in 0..MAX_LOCKOUT_HISTORY + 42 {
-                if let Some(v) = vote_state.as_mut() {
-                    vote_state::process_slot_vote_unchecked(v, i as u64)
-                }
-                let versioned = VoteStateVersions::Current(Box::new(vote_state.take().unwrap()));
-                vote_state::to(&versioned, &mut vote_account).unwrap();
-                match versioned {
-                    VoteStateVersions::Current(v) => {
-                        vote_state = Some(*v);
-                    }
-                    _ => panic!("Has to be of type Current"),
-                };
-            }
-            bank.store_account_and_update_capitalization(&vote_id, &vote_account);
-        }
-
-        let (bank, bank_forks) = bank.wrap_with_bank_forks_for_tests();
-        let bank = new_bank_from_parent_with_bank_forks(
-            &bank_forks,
-            bank,
-            &Pubkey::default(),
-            starting_slot,
-        );
-
-        assert!(!bank.is_partitioned_rewards_feature_enabled());
-        // Slot before the epoch boundary contains empty rewards (since fees are
-        // off), and no partitions because feature is inactive
-        assert_eq!(
-            bank.get_rewards_and_num_partitions(),
-            KeyedRewardsAndNumPartitions {
-                keyed_rewards: vec![],
-                num_partitions: None,
-            }
-        );
-
-        let epoch_boundary_bank = Arc::new(Bank::new_from_parent(
-            bank,
-            &Pubkey::default(),
-            SLOTS_PER_EPOCH,
-        ));
-        assert!(!epoch_boundary_bank.is_partitioned_rewards_feature_enabled());
-        // Slot at the epoch boundary contains voting rewards and staking rewards; still no partitions
-        let KeyedRewardsAndNumPartitions {
-            keyed_rewards,
-            num_partitions,
-        } = epoch_boundary_bank.get_rewards_and_num_partitions();
-        let mut voting_rewards_count = 0;
-        let mut staking_rewards_count = 0;
-        for (_pubkey, reward) in keyed_rewards.iter() {
-            match reward.reward_type {
-                RewardType::Voting => {
-                    voting_rewards_count += 1;
-                }
-                RewardType::Staking => {
-                    staking_rewards_count += 1;
-                }
-                _ => {}
-            }
-        }
-        assert_eq!(
-            keyed_rewards.len(),
-            voting_rewards_count + staking_rewards_count
-        );
-        assert_eq!(voting_rewards_count, num_rewards);
-        assert_eq!(staking_rewards_count, num_rewards);
-        assert!(num_partitions.is_none());
-
-        let bank =
-            Bank::new_from_parent(epoch_boundary_bank, &Pubkey::default(), SLOTS_PER_EPOCH + 1);
-        assert!(!bank.is_partitioned_rewards_feature_enabled());
-        // Slot after the epoch boundary contains empty rewards (since fees are
-        // off), and no partitions because feature is inactive
-        assert_eq!(
-            bank.get_rewards_and_num_partitions(),
-            KeyedRewardsAndNumPartitions {
-                keyed_rewards: vec![],
-                num_partitions: None,
-            }
-        );
-    }
-
     #[test]
     fn test_rewards_and_partitions_should_record() {
         let reward = RewardInfo {

+ 7 - 43
runtime/src/bank/partitioned_epoch_rewards/sysvar.rs

@@ -3,7 +3,7 @@ use {
     log::info,
     solana_sdk::{
         account::{create_account_shared_data_with_fields as create_account, from_account},
-        feature_set, sysvar,
+        sysvar,
     },
     solana_stake_program::points::PointValue,
 };
@@ -25,23 +25,12 @@ impl Bank {
     /// last_blockhash.
     pub(in crate::bank) fn create_epoch_rewards_sysvar(
         &self,
-        total_rewards: u64,
         distributed_rewards: u64,
         distribution_starting_block_height: u64,
         num_partitions: u64,
         point_value: PointValue,
     ) {
-        assert!(self.is_partitioned_rewards_code_enabled());
-
-        let total_rewards = if self
-            .feature_set
-            .is_active(&feature_set::partitioned_epoch_rewards_superfeature::id())
-        {
-            point_value.rewards
-        } else {
-            total_rewards
-        };
-        assert!(total_rewards >= distributed_rewards);
+        assert!(point_value.rewards >= distributed_rewards);
 
         let parent_blockhash = self.last_blockhash();
 
@@ -50,7 +39,7 @@ impl Bank {
             num_partitions,
             parent_blockhash,
             total_points: point_value.points,
-            total_rewards,
+            total_rewards: point_value.rewards,
             distributed_rewards,
             active: true,
         };
@@ -70,8 +59,6 @@ impl Bank {
         &self,
         distributed: u64,
     ) {
-        assert!(self.is_partitioned_rewards_code_enabled());
-
         let mut epoch_rewards = self.get_epoch_rewards_sysvar();
         assert!(epoch_rewards.active);
 
@@ -90,17 +77,7 @@ impl Bank {
     /// Update EpochRewards sysvar with distributed rewards
     pub(in crate::bank::partitioned_epoch_rewards) fn set_epoch_rewards_sysvar_to_inactive(&self) {
         let mut epoch_rewards = self.get_epoch_rewards_sysvar();
-        if self
-            .feature_set
-            .is_active(&feature_set::partitioned_epoch_rewards_superfeature::id())
-        {
-            assert!(epoch_rewards.total_rewards >= epoch_rewards.distributed_rewards);
-        } else {
-            assert_eq!(
-                epoch_rewards.distributed_rewards,
-                epoch_rewards.total_rewards
-            );
-        }
+        assert!(epoch_rewards.total_rewards >= epoch_rewards.distributed_rewards);
         epoch_rewards.active = false;
 
         self.update_sysvar_account(&sysvar::epoch_rewards::id(), |account| {
@@ -147,8 +124,7 @@ mod tests {
         let (mut genesis_config, _mint_keypair) =
             create_genesis_config(1_000_000 * LAMPORTS_PER_SOL);
         genesis_config.epoch_schedule = EpochSchedule::custom(432000, 432000, false);
-        let mut bank = Bank::new_for_tests(&genesis_config);
-        bank.activate_feature(&solana_feature_set::partitioned_epoch_rewards_superfeature::id());
+        let bank = Bank::new_for_tests(&genesis_config);
 
         let total_rewards = 1_000_000_000;
         let num_partitions = 2; // num_partitions is arbitrary and unimportant for this test
@@ -175,13 +151,7 @@ mod tests {
             sysvar::epoch_rewards::EpochRewards::default()
         );
 
-        bank.create_epoch_rewards_sysvar(
-            total_rewards,
-            10,
-            42,
-            num_partitions,
-            point_value.clone(),
-        );
+        bank.create_epoch_rewards_sysvar(10, 42, num_partitions, point_value.clone());
         let account = bank.get_account(&sysvar::epoch_rewards::id()).unwrap();
         let expected_balance = bank.get_minimum_balance_for_rent_exemption(account.data().len());
         // Expected balance is the sysvar rent-exempt balance
@@ -195,13 +165,7 @@ mod tests {
         let bank = Bank::new_from_parent(Arc::new(bank), &Pubkey::default(), parent_slot + 1);
         // Also note that running `create_epoch_rewards_sysvar()` against a bank
         // with an existing EpochRewards sysvar clobbers the previous values
-        bank.create_epoch_rewards_sysvar(
-            total_rewards,
-            10,
-            42,
-            num_partitions,
-            point_value.clone(),
-        );
+        bank.create_epoch_rewards_sysvar(10, 42, num_partitions, point_value.clone());
 
         let expected_epoch_rewards = sysvar::epoch_rewards::EpochRewards {
             distribution_starting_block_height: 42,

+ 1 - 4
runtime/src/bank/sysvar_cache.rs

@@ -5,7 +5,6 @@ use super::Bank;
 mod tests {
     use {
         super::*,
-        solana_feature_set as feature_set,
         solana_sdk::{
             genesis_config::create_genesis_config, pubkey::Pubkey,
             sysvar::epoch_rewards::EpochRewards,
@@ -82,7 +81,7 @@ mod tests {
         let (genesis_config, _mint_keypair) = create_genesis_config(100_000);
         let bank0 = Arc::new(Bank::new_for_tests(&genesis_config));
         let bank1_slot = bank0.slot() + 1;
-        let mut bank1 = Bank::new_from_parent(bank0, &Pubkey::default(), bank1_slot);
+        let bank1 = Bank::new_from_parent(bank0, &Pubkey::default(), bank1_slot);
 
         let bank1_sysvar_cache = bank1.transaction_processor.sysvar_cache();
         let bank1_cached_clock = bank1_sysvar_cache.get_clock();
@@ -111,7 +110,6 @@ mod tests {
         drop(bank1_sysvar_cache);
 
         // inject a reward sysvar for test
-        bank1.activate_feature(&feature_set::partitioned_epoch_rewards_superfeature::id());
         let num_partitions = 2; // num_partitions is arbitrary and unimportant for this test
         let total_points = 42_000; // total_points is arbitrary for the purposes of this test
         let expected_epoch_rewards = EpochRewards {
@@ -124,7 +122,6 @@ mod tests {
             active: true,
         };
         bank1.create_epoch_rewards_sysvar(
-            expected_epoch_rewards.total_rewards,
             expected_epoch_rewards.distributed_rewards,
             expected_epoch_rewards.distribution_starting_block_height,
             num_partitions,

+ 167 - 43
runtime/src/bank/tests.rs

@@ -14,6 +14,8 @@ use {
             genesis_sysvar_and_builtin_program_lamports, GenesisConfigInfo, ValidatorVoteKeypairs,
         },
         snapshot_bank_utils, snapshot_utils,
+        stake_history::StakeHistory,
+        stakes::InvalidCacheEntryReason,
         status_cache::MAX_CACHE_ENTRIES,
     },
     agave_transaction_view::static_account_keys_frame::MAX_STATIC_ACCOUNTS_PER_PACKET,
@@ -21,7 +23,7 @@ use {
     crossbeam_channel::{bounded, unbounded},
     itertools::Itertools,
     rand::Rng,
-    rayon::ThreadPoolBuilder,
+    rayon::{ThreadPool, ThreadPoolBuilder},
     serde::{Deserialize, Serialize},
     solana_accounts_db::{
         accounts::AccountAddressFilter,
@@ -412,6 +414,11 @@ fn bank1_sysvar_delta() -> u64 {
     SLOT_HASHES_SYSVAR_MIN_BALANCE
 }
 
+fn bank2_sysvar_delta() -> u64 {
+    const EPOCH_REWARDS_SYSVAR_MIN_BALANCE: u64 = 1_454_640;
+    EPOCH_REWARDS_SYSVAR_MIN_BALANCE
+}
+
 #[test]
 fn test_bank_capitalization() {
     let bank0 = Arc::new(Bank::new_for_tests(&GenesisConfig {
@@ -1899,10 +1906,106 @@ fn test_bank_update_vote_stake_rewards() {
     });
 }
 
+impl Bank {
+    fn _load_vote_and_stake_accounts(
+        &self,
+        thread_pool: &ThreadPool,
+        reward_calc_tracer: Option<impl RewardCalcTracer>,
+    ) -> StakeDelegationsMap {
+        let stakes = self.stakes_cache.stakes();
+        let stake_delegations = self.filter_stake_delegations(&stakes);
+        // Obtain all unique voter pubkeys from stake delegations.
+        fn merge(mut acc: HashSet<Pubkey>, other: HashSet<Pubkey>) -> HashSet<Pubkey> {
+            if acc.len() < other.len() {
+                return merge(other, acc);
+            }
+            acc.extend(other);
+            acc
+        }
+        let voter_pubkeys = thread_pool.install(|| {
+            stake_delegations
+                .par_iter()
+                .fold(
+                    HashSet::default,
+                    |mut voter_pubkeys, (_stake_pubkey, stake_account)| {
+                        voter_pubkeys.insert(stake_account.delegation().voter_pubkey);
+                        voter_pubkeys
+                    },
+                )
+                .reduce(HashSet::default, merge)
+        });
+        // Obtain vote-accounts for unique voter pubkeys.
+        let cached_vote_accounts = stakes.vote_accounts();
+        let solana_vote_program: Pubkey = solana_vote_program::id();
+        let vote_accounts_cache_miss_count = AtomicUsize::default();
+        let get_vote_account = |vote_pubkey: &Pubkey| -> Option<VoteAccount> {
+            if let Some(vote_account) = cached_vote_accounts.get(vote_pubkey) {
+                return Some(vote_account.clone());
+            }
+            // If accounts-db contains a valid vote account, then it should
+            // already have been cached in cached_vote_accounts; so the code
+            // below is only for sanity check, and can be removed once
+            // vote_accounts_cache_miss_count is shown to be always zero.
+            let account = self.get_account_with_fixed_root(vote_pubkey)?;
+            if account.owner() == &solana_vote_program
+                && VoteState::deserialize(account.data()).is_ok()
+            {
+                vote_accounts_cache_miss_count.fetch_add(1, Relaxed);
+            }
+            VoteAccount::try_from(account).ok()
+        };
+        let invalid_vote_keys = DashMap::<Pubkey, InvalidCacheEntryReason>::new();
+        let make_vote_delegations_entry = |vote_pubkey| {
+            let Some(vote_account) = get_vote_account(&vote_pubkey) else {
+                invalid_vote_keys.insert(vote_pubkey, InvalidCacheEntryReason::Missing);
+                return None;
+            };
+            if vote_account.owner() != &solana_vote_program {
+                invalid_vote_keys.insert(vote_pubkey, InvalidCacheEntryReason::WrongOwner);
+                return None;
+            }
+            let stake_delegations = Vec::default();
+            Some((vote_pubkey, stake_delegations))
+        };
+        let stake_delegations_map: DashMap<Pubkey, StakeDelegations> = thread_pool.install(|| {
+            voter_pubkeys
+                .into_par_iter()
+                .filter_map(make_vote_delegations_entry)
+                .collect()
+        });
+        // Join stake accounts with vote-accounts.
+        let push_stake_delegation = |(stake_pubkey, stake_account): (&Pubkey, &StakeAccount<_>)| {
+            let delegation = stake_account.delegation();
+            let Some(mut vote_delegations) =
+                stake_delegations_map.get_mut(&delegation.voter_pubkey)
+            else {
+                return;
+            };
+            if let Some(reward_calc_tracer) = reward_calc_tracer.as_ref() {
+                let delegation =
+                    InflationPointCalculationEvent::Delegation(*delegation, solana_vote_program);
+                let event = RewardCalculationEvent::Staking(stake_pubkey, &delegation);
+                reward_calc_tracer(&event);
+            }
+            let stake_delegation = (*stake_pubkey, stake_account.clone());
+            vote_delegations.push(stake_delegation);
+        };
+        thread_pool.install(|| {
+            stake_delegations
+                .into_par_iter()
+                .for_each(push_stake_delegation);
+        });
+        stake_delegations_map
+    }
+}
+
+type StakeDelegations = Vec<(Pubkey, StakeAccount<Delegation>)>;
+type StakeDelegationsMap = DashMap<Pubkey, StakeDelegations>;
+
 #[cfg(test)]
 fn check_bank_update_vote_stake_rewards<F>(load_vote_and_stake_accounts: F)
 where
-    F: Fn(&Bank) -> LoadVoteAndStakeAccountsResult,
+    F: Fn(&Bank) -> StakeDelegationsMap,
 {
     solana_logger::setup();
 
@@ -1975,26 +2078,54 @@ where
 
     load_vote_and_stake_accounts(&bank0);
 
-    // put a child bank in epoch 1, which calls update_rewards()...
-    let bank1 = Bank::new_from_parent(
+    // put a child bank in epoch 1
+    let bank1 = Arc::new(Bank::new_from_parent(
         bank0.clone(),
         &Pubkey::default(),
         bank0.get_slots_in_epoch(bank0.epoch()) + 1,
-    );
+    ));
+
     // verify that there's inflation
     assert_ne!(bank1.capitalization(), bank0.capitalization());
 
+    // check voting rewards show up in rewards vector
+    assert_eq!(
+        *bank1.rewards.read().unwrap(),
+        vec![(
+            vote_id,
+            RewardInfo {
+                reward_type: RewardType::Voting,
+                lamports: 0,
+                post_balance: bank1.get_balance(&vote_id),
+                commission: Some(0),
+            }
+        ),]
+    );
+    bank1.freeze();
+
+    // advance past partitioned epoch staking rewards delivery
+    let bank2 = Arc::new(Bank::new_from_parent(
+        bank1.clone(),
+        &Pubkey::default(),
+        bank1.slot() + 1,
+    ));
+    // verify that there's inflation
+    assert_ne!(bank2.capitalization(), bank0.capitalization());
+
     // verify the inflation is represented in validator_points
-    let paid_rewards = bank1.capitalization() - bank0.capitalization() - bank1_sysvar_delta();
+    let paid_rewards = bank2.capitalization()
+        - bank0.capitalization()
+        - bank1_sysvar_delta()
+        - bank2_sysvar_delta();
 
-    // this assumes that no new builtins or precompiles were activated in bank1
+    // this assumes that no new builtins or precompiles were activated in bank1 or bank2
     let PrevEpochInflationRewards {
         validator_rewards, ..
-    } = bank1.calculate_previous_epoch_inflation_rewards(bank0.capitalization(), bank0.epoch());
+    } = bank2.calculate_previous_epoch_inflation_rewards(bank0.capitalization(), bank0.epoch());
 
     // verify the stake and vote accounts are the right size
     assert!(
-        ((bank1.get_balance(&stake_id) - stake_account.lamports() + bank1.get_balance(&vote_id)
+        ((bank2.get_balance(&stake_id) - stake_account.lamports() + bank2.get_balance(&vote_id)
             - vote_account.lamports()) as f64
             - validator_rewards as f64)
             .abs()
@@ -2004,34 +2135,24 @@ where
     // verify the rewards are the right size
     assert!((validator_rewards as f64 - paid_rewards as f64).abs() < 1.0); // rounding, truncating
 
-    // verify validator rewards show up in bank1.rewards vector
+    // verify validator rewards show up in rewards vectors
     assert_eq!(
-        *bank1.rewards.read().unwrap(),
-        vec![
-            (
-                vote_id,
-                RewardInfo {
-                    reward_type: RewardType::Voting,
-                    lamports: 0,
-                    post_balance: bank1.get_balance(&vote_id),
-                    commission: Some(0),
-                }
-            ),
-            (
-                stake_id,
-                RewardInfo {
-                    reward_type: RewardType::Staking,
-                    lamports: validator_rewards as i64,
-                    post_balance: bank1.get_balance(&stake_id),
-                    commission: Some(0),
-                }
-            )
-        ]
+        *bank2.rewards.read().unwrap(),
+        vec![(
+            stake_id,
+            RewardInfo {
+                reward_type: RewardType::Staking,
+                lamports: validator_rewards as i64,
+                post_balance: bank2.get_balance(&stake_id),
+                commission: Some(0),
+            }
+        )]
     );
-    bank1.freeze();
+    bank2.freeze();
     add_root_and_flush_write_cache(&bank0);
     add_root_and_flush_write_cache(&bank1);
-    assert!(bank1.calculate_and_verify_capitalization(true));
+    add_root_and_flush_write_cache(&bank2);
+    assert!(bank2.calculate_and_verify_capitalization(true));
 }
 
 fn do_test_bank_update_rewards_determinism() -> u64 {
@@ -2098,11 +2219,11 @@ fn do_test_bank_update_rewards_determinism() -> u64 {
     bank.store_account_and_update_capitalization(&vote_id, &vote_account);
 
     // put a child bank in epoch 1, which calls update_rewards()...
-    let bank1 = Bank::new_from_parent(
+    let bank1 = Arc::new(Bank::new_from_parent(
         bank.clone(),
         &Pubkey::default(),
         bank.get_slots_in_epoch(bank.epoch()) + 1,
-    );
+    ));
     // verify that there's inflation
     assert_ne!(bank1.capitalization(), bank.capitalization());
 
@@ -2117,6 +2238,11 @@ fn do_test_bank_update_rewards_determinism() -> u64 {
         .iter()
         .find(|(_address, reward)| reward.reward_type == RewardType::Voting)
         .unwrap();
+
+    // put another child bank, since partitioned staking rewards are delivered
+    // after the epoch-boundary slot
+    let bank2 = Bank::new_from_parent(bank1.clone(), &Pubkey::default(), bank1.slot() + 1);
+    let rewards = bank2.rewards.read().unwrap();
     rewards
         .iter()
         .find(|(_address, reward)| reward.reward_type == RewardType::Staking)
@@ -6483,19 +6609,19 @@ fn test_bank_hash_consistency() {
         if bank.slot == 32 {
             assert_eq!(
                 bank.hash().to_string(),
-                "7FPfwBut4b7bXtKPsobQS1cuFgF47SZHDb4teQcJRomv"
+                "Hdrk5wqzRZbofSgZMC3ztfNimrFu6DeYp751JWvtabo"
             );
         }
         if bank.slot == 64 {
             assert_eq!(
                 bank.hash().to_string(),
-                "28CWiEuA3izdt5xe4LyS4Q1DTALmYgrVctSTazFiPVcW"
+                "4EcAFkTxymwwPGeCgadhkrkg2hqfAPzuQZoN2NFqPzyg"
             );
         }
         if bank.slot == 128 {
             assert_eq!(
                 bank.hash().to_string(),
-                "AdCmEvRXWKpvXb9fG6AFQhzGgB5ciAXnDajvaNK7YUg8"
+                "4BK3VANr5mhyRyrwbUHYb2kmM5m76PBGkhmKMrQ2aq7L"
             );
             break;
         }
@@ -9197,7 +9323,7 @@ fn test_epoch_schedule_from_genesis_config() {
 
 fn check_stake_vote_account_validity<F>(check_owner_change: bool, load_vote_and_stake_accounts: F)
 where
-    F: Fn(&Bank) -> LoadVoteAndStakeAccountsResult,
+    F: Fn(&Bank) -> StakeDelegationsMap,
 {
     let validator_vote_keypairs0 = ValidatorVoteKeypairs::new_rand();
     let validator_vote_keypairs1 = ValidatorVoteKeypairs::new_rand();
@@ -9221,8 +9347,7 @@ where
         None,
         None,
     ));
-    let vote_and_stake_accounts =
-        load_vote_and_stake_accounts(&bank).vote_with_stake_delegations_map;
+    let vote_and_stake_accounts = load_vote_and_stake_accounts(&bank);
     assert_eq!(vote_and_stake_accounts.len(), 2);
 
     let mut vote_account = bank
@@ -9261,8 +9386,7 @@ where
     );
 
     // Accounts must be valid stake and vote accounts
-    let vote_and_stake_accounts =
-        load_vote_and_stake_accounts(&bank).vote_with_stake_delegations_map;
+    let vote_and_stake_accounts = load_vote_and_stake_accounts(&bank);
     assert_eq!(
         vote_and_stake_accounts.len(),
         usize::from(!check_owner_change)

+ 1 - 74
runtime/src/stakes.rs

@@ -2,16 +2,13 @@
 //! node stakes
 use {
     crate::{stake_account, stake_history::StakeHistory},
-    dashmap::DashMap,
     im::HashMap as ImHashMap,
     log::error,
     num_derive::ToPrimitive,
-    num_traits::ToPrimitive,
     rayon::{prelude::*, ThreadPool},
-    solana_accounts_db::stake_rewards::StakeReward,
     solana_sdk::{
         account::{AccountSharedData, ReadableAccount},
-        clock::{Epoch, Slot},
+        clock::Epoch,
         pubkey::Pubkey,
         stake::state::{Delegation, StakeActivationStatus},
         vote::state::VoteStateVersions,
@@ -150,43 +147,6 @@ impl StakesCache {
         let mut stakes = self.0.write().unwrap();
         stakes.activate_epoch(next_epoch, thread_pool, new_rate_activation_epoch)
     }
-
-    pub(crate) fn update_stake_accounts(
-        &self,
-        thread_pool: &ThreadPool,
-        stake_rewards: &[StakeReward],
-        new_rate_activation_epoch: Option<Epoch>,
-    ) {
-        self.0.write().unwrap().update_stake_accounts(
-            thread_pool,
-            stake_rewards,
-            new_rate_activation_epoch,
-        )
-    }
-
-    pub(crate) fn handle_invalid_keys(
-        &self,
-        invalid_vote_keys: DashMap<Pubkey, InvalidCacheEntryReason>,
-        current_slot: Slot,
-    ) {
-        if invalid_vote_keys.is_empty() {
-            return;
-        }
-
-        // Prune invalid stake delegations and vote accounts that were
-        // not properly evicted in normal operation.
-        let mut stakes = self.0.write().unwrap();
-
-        for (vote_pubkey, reason) in invalid_vote_keys {
-            stakes.remove_vote_account(&vote_pubkey);
-            datapoint_warn!(
-                "bank-stake_delegation_accounts-invalid-account",
-                ("slot", current_slot as i64, i64),
-                ("vote-address", format!("{vote_pubkey:?}"), String),
-                ("reason", reason.to_i64().unwrap_or_default(), i64),
-            );
-        }
-    }
 }
 
 /// The generic type T is either Delegation or StakeAccount.
@@ -464,39 +424,6 @@ impl Stakes<StakeAccount> {
         }
     }
 
-    fn update_stake_accounts(
-        &mut self,
-        thread_pool: &ThreadPool,
-        stake_rewards: &[StakeReward],
-        new_rate_activation_epoch: Option<Epoch>,
-    ) {
-        let stake_delegations: Vec<_> = thread_pool.install(|| {
-            stake_rewards
-                .into_par_iter()
-                .filter_map(|stake_reward| {
-                    let stake_account = StakeAccount::try_from(stake_reward.stake_account.clone());
-                    Some((stake_reward.stake_pubkey, stake_account.ok()?))
-                })
-                .collect()
-        });
-        self.stake_delegations = std::mem::take(&mut self.stake_delegations)
-            .into_iter()
-            .chain(stake_delegations)
-            .collect::<HashMap<Pubkey, StakeAccount>>()
-            .into_iter()
-            .filter(|(_, account)| account.lamports() != 0u64)
-            .collect();
-        let stake_delegations: Vec<_> = self.stake_delegations.values().collect();
-        self.vote_accounts = refresh_vote_accounts(
-            thread_pool,
-            self.epoch,
-            &self.vote_accounts,
-            &stake_delegations,
-            &self.stake_history,
-            new_rate_activation_epoch,
-        );
-    }
-
     pub(crate) fn stake_delegations(&self) -> &ImHashMap<Pubkey, StakeAccount> {
         &self.stake_delegations
     }

+ 0 - 23
validator/src/cli.rs

@@ -1474,29 +1474,6 @@ pub fn app<'a>(version: &'a str, default_args: &'a DefaultArgs) -> App<'a, 'a> {
                 .takes_value(true)
                 .help("Number of bins to divide the accounts index into"),
         )
-        .arg(
-            Arg::with_name("partitioned_epoch_rewards_compare_calculation")
-                .long("partitioned-epoch-rewards-compare-calculation")
-                .takes_value(false)
-                .help(
-                    "Do normal epoch rewards distribution, but also calculate rewards using the \
-                     partitioned rewards code path and compare the resulting vote and stake \
-                     accounts",
-                )
-                .hidden(hidden_unless_forced()),
-        )
-        .arg(
-            Arg::with_name("partitioned_epoch_rewards_force_enable_single_slot")
-                .long("partitioned-epoch-rewards-force-enable-single-slot")
-                .takes_value(false)
-                .help(
-                    "Force the partitioned rewards distribution, but distribute all rewards in \
-                     the first slot in the epoch. This should match consensus with the normal \
-                     rewards distribution.",
-                )
-                .conflicts_with("partitioned_epoch_rewards_compare_calculation")
-                .hidden(hidden_unless_forced()),
-        )
         .arg(
             Arg::with_name("accounts_index_path")
                 .long("accounts-index-path")

+ 0 - 11
validator/src/main.rs

@@ -23,7 +23,6 @@ use {
             AccountIndex, AccountSecondaryIndexes, AccountSecondaryIndexesIncludeExclude,
             AccountsIndexConfig, IndexLimitMb, ScanFilter,
         },
-        partitioned_rewards::TestPartitionedEpochRewards,
         utils::{
             create_all_accounts_run_and_snapshot_dirs, create_and_canonicalize_directories,
             create_and_canonicalize_directory,
@@ -1229,15 +1228,6 @@ pub fn main() {
         accounts_index_config.bins = Some(bins);
     }
 
-    let test_partitioned_epoch_rewards =
-        if matches.is_present("partitioned_epoch_rewards_compare_calculation") {
-            TestPartitionedEpochRewards::CompareResults
-        } else if matches.is_present("partitioned_epoch_rewards_force_enable_single_slot") {
-            TestPartitionedEpochRewards::ForcePartitionedEpochRewardsInOneBlock
-        } else {
-            TestPartitionedEpochRewards::None
-        };
-
     accounts_index_config.index_limit_mb = if matches.is_present("disable_accounts_disk_index") {
         IndexLimitMb::InMemOnly
     } else {
@@ -1362,7 +1352,6 @@ pub fn main() {
         .ok(),
         exhaustively_verify_refcounts: matches.is_present("accounts_db_verify_refcounts"),
         create_ancient_storage,
-        test_partitioned_epoch_rewards,
         test_skip_rewrites_but_include_in_bank_hash: matches
             .is_present("accounts_db_test_skip_rewrites"),
         storage_access,