/// <summary> /// Initiate the exit of the validator with index ``index``. /// </summary> public void InitiateValidatorExit(BeaconState state, ValidatorIndex index) { // Return if validator already initiated exit var validator = state.Validators[(int)(ulong)index]; if (validator.ExitEpoch != _chainConstants.FarFutureEpoch) { return; } // Compute exit queue epoch var exitEpochs = state.Validators .Where(x => x.ExitEpoch != _chainConstants.FarFutureEpoch) .Select(x => x.ExitEpoch); var maxExitEpoch = exitEpochs.DefaultIfEmpty().Max(); var currentEpoch = _beaconStateAccessor.GetCurrentEpoch(state); var activationExitEpoch = _beaconChainUtility.ComputeActivationExitEpoch(currentEpoch); var exitQueueEpoch = Epoch.Max(maxExitEpoch, activationExitEpoch); var exitQueueChurn = state.Validators.Where(x => x.ExitEpoch == exitQueueEpoch).Count(); var validatorChurnLimit = _beaconStateAccessor.GetValidatorChurnLimit(state); if ((ulong)exitQueueChurn >= validatorChurnLimit) { exitQueueEpoch += new Epoch(1); } // Set validator exit epoch and withdrawable epoch validator.SetExitEpoch(exitQueueEpoch); var withdrawableEpoch = validator.ExitEpoch + _timeParameterOptions.CurrentValue.MinimumValidatorWithdrawabilityDelay; validator.SetWithdrawableEpoch(withdrawableEpoch); }
public void ProcessRegistryUpdates(BeaconState state) { _logger.LogInformation(Event.ProcessRegistryUpdates, "Process epoch registry updates state {BeaconState}", state); var gweiValues = _gweiValueOptions.CurrentValue; // Process activation eligibility and ejections var currentEpoch = _beaconStateAccessor.GetCurrentEpoch(state); for (var index = 0; index < state.Validators.Count; index++) { var validator = state.Validators[index]; if (validator.ActivationEligibilityEpoch == _chainConstants.FarFutureEpoch && validator.EffectiveBalance == gweiValues.MaximumEffectiveBalance) { validator.SetEligible(currentEpoch); } var isActive = _beaconChainUtility.IsActiveValidator(validator, currentEpoch); if (isActive && validator.EffectiveBalance <= gweiValues.EjectionBalance) { _beaconStateMutator.InitiateValidatorExit(state, new ValidatorIndex((ulong)index)); } } // Queue validators eligible for activation and not dequeued for activation prior to finalized epoch var activationExitEpoch = _beaconChainUtility.ComputeActivationExitEpoch(state.FinalizedCheckpoint.Epoch); var activationQueue = state.Validators .Select((validator, index) => new { index, validator }) .Where(x => x.validator.ActivationEligibilityEpoch != _chainConstants.FarFutureEpoch && x.validator.ActivationEpoch >= activationExitEpoch) .OrderBy(x => x.validator.ActivationEligibilityEpoch) .Select(x => x.index); // Dequeued validators for activation up to churn limit (without resetting activation epoch) var validatorChurnLimit = _beaconStateAccessor.GetValidatorChurnLimit(state); var activationEpoch = _beaconChainUtility.ComputeActivationExitEpoch(currentEpoch); foreach (var index in activationQueue.Take((int)validatorChurnLimit)) { var validator = state.Validators[index]; if (validator.ActivationEpoch == _chainConstants.FarFutureEpoch) { validator.SetActive(activationEpoch); } } }