@@ -1237,9 +1237,7 @@ pub mod pallet {
12371237 // This is bounded by max allowed number of stake entries per account.
12381238 let to_be_deleted: Vec < T :: SmartContract > = StakerInfo :: < T > :: iter_prefix ( & account)
12391239 . filter_map ( |( smart_contract, stake_info) | {
1240- if stake_info. period_number ( ) < current_period
1241- && !stake_info. is_bonus_eligible ( )
1242- || stake_info. period_number ( ) < threshold_period
1240+ if Self :: is_expired_staker_entry ( & stake_info, current_period, threshold_period)
12431241 {
12441242 Some ( smart_contract)
12451243 } else {
@@ -1788,6 +1786,16 @@ pub mod pallet {
17881786 current_period. saturating_sub ( T :: RewardRetentionInPeriods :: get ( ) )
17891787 }
17901788
1789+ /// Returns `true` when the staking entry can be removed, meaning it is past the claim window and with no claimable bonus reward.
1790+ fn is_expired_staker_entry (
1791+ info : & SingularStakingInfo ,
1792+ current_period : PeriodNumber ,
1793+ threshold_period : PeriodNumber ,
1794+ ) -> bool {
1795+ ( info. period_number ( ) < current_period && !info. is_bonus_eligible ( ) )
1796+ || info. period_number ( ) < threshold_period
1797+ }
1798+
17911799 /// Unlocking period expressed in the number of blocks.
17921800 pub fn unlocking_period ( ) -> BlockNumber {
17931801 T :: CycleConfiguration :: blocks_per_era ( ) . saturating_mul ( T :: UnlockingPeriod :: get ( ) . into ( ) )
@@ -2283,12 +2291,12 @@ pub mod pallet {
22832291 . staked_period ( )
22842292 . ok_or ( Error :: < T > :: NoClaimableRewards ) ?;
22852293
2286- // Check if the rewards have expired
22872294 let protocol_state = ActiveProtocolState :: < T > :: get ( ) ;
2288- ensure ! (
2289- staked_period >= Self :: oldest_claimable_period( protocol_state. period_number( ) ) ,
2290- Error :: <T >:: RewardExpired
2291- ) ;
2295+ let current_period = protocol_state. period_number ( ) ;
2296+ let threshold_period = Self :: oldest_claimable_period ( current_period) ;
2297+
2298+ // Check if the rewards have expired
2299+ ensure ! ( staked_period >= threshold_period, Error :: <T >:: RewardExpired ) ;
22922300
22932301 // Calculate the reward claim span
22942302 let earliest_staked_era = ledger
@@ -2300,7 +2308,7 @@ pub mod pallet {
23002308
23012309 // The last era for which we can theoretically claim rewards.
23022310 // And indicator if we know the period's ending era.
2303- let ( last_period_era, period_end) = if staked_period == protocol_state . period_number ( ) {
2311+ let ( last_period_era, period_end) = if staked_period == current_period {
23042312 ( protocol_state. era . saturating_sub ( 1 ) , None )
23052313 } else {
23062314 PeriodEnd :: < T > :: get ( & staked_period)
@@ -2343,6 +2351,25 @@ pub mod pallet {
23432351 T :: StakingRewardHandler :: payout_reward ( & account, reward_sum)
23442352 . map_err ( |_| Error :: < T > :: RewardPayoutFailed ) ?;
23452353
2354+ let stale_contracts: Vec < T :: SmartContract > = StakerInfo :: < T > :: iter_prefix ( & account)
2355+ . filter_map ( |( smart_contract, stake_info) | {
2356+ if Self :: is_expired_staker_entry ( & stake_info, current_period, threshold_period)
2357+ {
2358+ Some ( smart_contract)
2359+ } else {
2360+ None
2361+ }
2362+ } )
2363+ . collect ( ) ;
2364+
2365+ if !stale_contracts. is_empty ( ) {
2366+ let removed: u32 = stale_contracts. len ( ) . unique_saturated_into ( ) ;
2367+ for contract in stale_contracts {
2368+ StakerInfo :: < T > :: remove ( & account, & contract) ;
2369+ }
2370+ ledger. contract_stake_count . saturating_reduce ( removed) ;
2371+ }
2372+
23462373 Self :: update_ledger ( & account, ledger) ?;
23472374
23482375 rewards. into_iter ( ) . for_each ( |( era, reward) | {
0 commit comments