/// <summary> /// Return the sequence of active validator indices at ``epoch``. /// </summary> public IList <ValidatorIndex> GetActiveValidatorIndices(BeaconState state, Epoch epoch) { return(state.Validators .Select((validator, index) => new { validator, index }) .Where(x => _beaconChainUtility.IsActiveValidator(x.validator, epoch)) .Select(x => (ValidatorIndex)(ulong)x.index) .ToList()); }
public (IList <Gwei> rewards, IList <Gwei> penalties) GetAttestationDeltas(BeaconState state) { var rewardsAndPenalties = _rewardsAndPenaltiesOptions.CurrentValue; var previousEpoch = _beaconStateAccessor.GetPreviousEpoch(state); var totalBalance = _beaconStateAccessor.GetTotalActiveBalance(state); var validatorCount = state.Validators.Count; var rewards = Enumerable.Repeat(Gwei.Zero, validatorCount).ToList(); var penalties = Enumerable.Repeat(Gwei.Zero, validatorCount).ToList(); var eligibleValidatorIndices = new List <ValidatorIndex>(); for (var index = 0; index < validatorCount; index++) { var validator = state.Validators[index]; var isActive = _beaconChainUtility.IsActiveValidator(validator, previousEpoch); if (isActive || (validator.IsSlashed && previousEpoch + new Epoch(1) < validator.WithdrawableEpoch)) { eligibleValidatorIndices.Add(new ValidatorIndex((ulong)index)); } } // Micro-incentives for matching FFG source, FFG target, and head var matchingSourceAttestations = GetMatchingSourceAttestations(state, previousEpoch); var matchingTargetAttestations = GetMatchingTargetAttestations(state, previousEpoch); var matchingHeadAttestations = GetMatchingHeadAttestations(state, previousEpoch); var attestationSets = new[] { matchingSourceAttestations, matchingTargetAttestations, matchingHeadAttestations }; var setNames = new[] { "Source", "Target", "Head" }; var setIndex = 0; foreach (var attestationSet in attestationSets) { var unslashedAttestingIndices = GetUnslashedAttestingIndices(state, attestationSet); var attestingBalance = _beaconStateAccessor.GetTotalBalance(state, unslashedAttestingIndices); foreach (var index in eligibleValidatorIndices) { if (unslashedAttestingIndices.Contains(index)) { var reward = (GetBaseReward(state, index) * (ulong)attestingBalance) / (ulong)totalBalance; _logger.LogDebug(0, "Reward validator {ValidatorIndex} matching {SetName} +{Reward}", index, setNames[setIndex], reward); rewards[(int)(ulong)index] += reward; } else { var penalty = GetBaseReward(state, index); _logger.LogDebug(0, "Penalty validator {ValidatorIndex} non-matching {SetName} -{Penalty}", index, setNames[setIndex], penalty); penalties[(int)(ulong)index] += penalty; } } setIndex++; } // Proposer and inclusion delay micro-rewards var unslashedSourceAttestingIndices = GetUnslashedAttestingIndices(state, matchingSourceAttestations); foreach (var index in unslashedSourceAttestingIndices) { var attestation = matchingSourceAttestations .Where(x => { var attestingIndices = _beaconStateAccessor.GetAttestingIndices(state, x.Data, x.AggregationBits); return(attestingIndices.Contains(index)); }) .OrderBy(x => x.InclusionDelay) .First(); var baseReward = GetBaseReward(state, index); var proposerReward = baseReward / rewardsAndPenalties.ProposerRewardQuotient; _logger.LogDebug(0, "Reward validator {ValidatorIndex} proposer +{Reward}", attestation.ProposerIndex, proposerReward); rewards[(int)(ulong)attestation.ProposerIndex] += proposerReward; var maxAttesterReward = baseReward - proposerReward; var attesterReward = maxAttesterReward / (ulong)attestation.InclusionDelay; _logger.LogDebug(0, "Reward validator {ValidatorIndex} attester inclusion delay +{Reward}", index, attesterReward); rewards[(int)(ulong)index] += attesterReward; } // Inactivity penalty var finalityDelay = previousEpoch - state.FinalizedCheckpoint.Epoch; if (finalityDelay > _timeParameterOptions.CurrentValue.MinimumEpochsToInactivityPenalty) { var matchingTargetAttestingIndices = GetUnslashedAttestingIndices(state, matchingTargetAttestations); foreach (var index in eligibleValidatorIndices) { var delayPenalty = GetBaseReward(state, index) * _chainConstants.BaseRewardsPerEpoch; _logger.LogDebug(0, "Penalty validator {ValidatorIndex} finality delay -{Penalty}", index, delayPenalty); penalties[(int)(ulong)index] += delayPenalty; if (!matchingTargetAttestingIndices.Contains(index)) { var effectiveBalance = state.Validators[(int)(ulong)index].EffectiveBalance; var additionalInactivityPenalty = (effectiveBalance * (ulong)finalityDelay) / rewardsAndPenalties.InactivityPenaltyQuotient; _logger.LogDebug(0, "Penalty validator {ValidatorIndex} inactivity -{Penalty}", index, additionalInactivityPenalty); penalties[(int)(ulong)index] += additionalInactivityPenalty; } } } return(rewards, penalties); }