@@ -11,6 +11,7 @@ const epoch_helper = @import("../../consensus/helpers/epoch.zig");
1111const shuffle_helper = @import ("../../consensus/helpers/shuffle.zig" );
1212const balance_helper = @import ("../../consensus/helpers/balance.zig" );
1313const committee_helper = @import ("../../consensus/helpers/committee.zig" );
14+ const finality_helper = @import ("../../consensus/helpers/finality.zig" );
1415
1516/// Check if a validator is active at a given epoch.
1617/// A validator is active if the current epoch is greater than or equal to the validator's activation epoch and less than the validator's exit epoch.
@@ -555,6 +556,44 @@ pub fn getEligibleValidatorIndices(state: *consensus.BeaconState, allocator: std
555556 return eligible .toOwnedSlice ();
556557}
557558
559+ pub fn processInactivityUpdates (state : * consensus.BeaconState , allocator : std.mem.Allocator ) ! void {
560+ // Skip the genesis epoch as score updates are based on the previous epoch participation
561+ if (epoch_helper .getCurrentEpoch (state ) == constants .GENESIS_EPOCH ) {
562+ return ;
563+ }
564+
565+ const participating_indices = try getUnslashedParticipatingIndices (state , constants .TIMELY_TARGET_FLAG_INDEX , epoch_helper .getPreviousEpoch (state ), allocator );
566+ defer allocator .free (participating_indices );
567+
568+ const eligible_indices = try getEligibleValidatorIndices (state , allocator );
569+ defer allocator .free (eligible_indices );
570+
571+ for (eligible_indices ) | index | {
572+ // Increase the inactivity score of inactive validators
573+ if (std .mem .containsAtLeast (primitives .ValidatorIndex , participating_indices , 1 , &[_ ]primitives.ValidatorIndex {index })) {
574+ state .inactivityScores ()[index ] -= @min (1 , state .inactivityScores ()[index ]);
575+ } else {
576+ state .inactivityScores ()[index ] += configs .ActiveConfig .get ().INACTIVITY_SCORE_BIAS ;
577+ }
578+ // Decrease the inactivity score of all eligible validators during a leak-free epoch
579+ if (! finality_helper .isInInactivityLeak (state )) {
580+ state .inactivityScores ()[index ] -= @min (configs .ActiveConfig .get ().INACTIVITY_SCORE_RECOVERY_RATE , state .inactivityScores ()[index ]);
581+ }
582+ }
583+ }
584+
585+ pub fn getBaseReward (state : * const consensus.BeaconState , index : primitives.ValidatorIndex , allocator : std.mem.Allocator ) ! primitives.Gwei {
586+ const increments = state .validators ()[index ].effective_balance / preset .ActivePreset .get ().EFFECTIVE_BALANCE_INCREMENT ;
587+ const base_reward_per_increment = try getBaseRewardPerIncrement (state , allocator );
588+ return increments * base_reward_per_increment ;
589+ }
590+
591+ pub fn getBaseRewardPerIncrement (state : * const consensus.BeaconState , allocator : std.mem.Allocator ) ! primitives.Gwei {
592+ const total_balance = try balance_helper .getTotalActiveBalance (state , allocator );
593+ const sqrt_balance = std .math .sqrt (total_balance );
594+ return @as (primitives .Gwei , @divFloor (preset .ActivePreset .get ().EFFECTIVE_BALANCE_INCREMENT * preset .ActivePreset .get ().BASE_REWARD_FACTOR , sqrt_balance ));
595+ }
596+
558597test "test getBalanceChurnLimit" {
559598 preset .ActivePreset .set (preset .Presets .minimal );
560599 defer preset .ActivePreset .reset ();
0 commit comments