/// <summary> /// Slash the validator with index ``slashed_index``. /// </summary> public void SlashValidator(BeaconState state, ValidatorIndex slashedIndex, ValidatorIndex?optionalWhistleblowerIndex) { RewardsAndPenalties rewardsAndPenalties = _rewardsAndPenaltiesOptions.CurrentValue; StateListLengths stateListLengths = _stateListLengthOptions.CurrentValue; Epoch epoch = _beaconStateAccessor.GetCurrentEpoch(state); InitiateValidatorExit(state, slashedIndex); Validator validator = state.Validators[(int)slashedIndex]; validator.SetSlashed(); Epoch slashedWithdrawableEpoch = (Epoch)(epoch + stateListLengths.EpochsPerSlashingsVector); Epoch withdrawableEpoch = Epoch.Max(validator.WithdrawableEpoch, slashedWithdrawableEpoch); validator.SetWithdrawableEpoch(withdrawableEpoch); Epoch slashingsIndex = (Epoch)(epoch % stateListLengths.EpochsPerSlashingsVector); state.SetSlashings(slashingsIndex, validator.EffectiveBalance); Gwei slashingPenalty = validator.EffectiveBalance / rewardsAndPenalties.MinimumSlashingPenaltyQuotient; DecreaseBalance(state, slashedIndex, slashingPenalty); // Apply proposer and whistleblower rewards ValidatorIndex proposerIndex = _beaconStateAccessor.GetBeaconProposerIndex(state); ValidatorIndex whistleblowerIndex = optionalWhistleblowerIndex ?? proposerIndex; Gwei whistleblowerReward = validator.EffectiveBalance / rewardsAndPenalties.WhistleblowerRewardQuotient; Gwei proposerReward = whistleblowerReward / rewardsAndPenalties.ProposerRewardQuotient; IncreaseBalance(state, proposerIndex, proposerReward); IncreaseBalance(state, whistleblowerIndex, whistleblowerReward - proposerReward); }
/// <summary> /// Initiate the exit of the validator with index ``index``. /// </summary> public void InitiateValidatorExit(BeaconState state, ValidatorIndex index) { // Return if validator already initiated exit Validator validator = state.Validators[(int)index]; if (validator.ExitEpoch != _chainConstants.FarFutureEpoch) { return; } // Compute exit queue epoch IEnumerable <Epoch> exitEpochs = state.Validators .Where(x => x.ExitEpoch != _chainConstants.FarFutureEpoch) .Select(x => x.ExitEpoch); Epoch maxExitEpoch = exitEpochs.DefaultIfEmpty().Max(); Epoch currentEpoch = _beaconStateAccessor.GetCurrentEpoch(state); Epoch activationExitEpoch = _beaconChainUtility.ComputeActivationExitEpoch(currentEpoch); Epoch exitQueueEpoch = Epoch.Max(maxExitEpoch, activationExitEpoch); int exitQueueChurn = state.Validators.Where(x => x.ExitEpoch == exitQueueEpoch).Count(); ulong validatorChurnLimit = _beaconStateAccessor.GetValidatorChurnLimit(state); if ((ulong)exitQueueChurn >= validatorChurnLimit) { exitQueueEpoch += new Epoch(1); } // Set validator exit epoch and withdrawable epoch validator.SetExitEpoch(exitQueueEpoch); Epoch withdrawableEpoch = validator.ExitEpoch + _timeParameterOptions.CurrentValue.MinimumValidatorWithdrawabilityDelay; validator.SetWithdrawableEpoch(withdrawableEpoch); }
/// <summary> /// Slash the validator with index ``slashed_index``. /// </summary> public void SlashValidator(BeaconState state, ValidatorIndex slashedIndex, ValidatorIndex whistleblowerIndex) { var rewardsAndPenalties = _rewardsAndPenaltiesOptions.CurrentValue; var stateListLengths = _stateListLengthOptions.CurrentValue; var epoch = _beaconStateAccessor.GetCurrentEpoch(state); InitiateValidatorExit(state, slashedIndex); var validator = state.Validators[(int)(ulong)slashedIndex]; validator.SetSlashed(); var slashedWithdrawableEpoch = epoch + stateListLengths.EpochsPerSlashingsVector; var withdrawableEpoch = Epoch.Max(validator.WithdrawableEpoch, slashedWithdrawableEpoch); validator.SetWithdrawableEpoch(withdrawableEpoch); var slashingsIndex = epoch % stateListLengths.EpochsPerSlashingsVector; state.SetSlashings(slashingsIndex, validator.EffectiveBalance); var slashingPenalty = validator.EffectiveBalance / rewardsAndPenalties.MinimumSlashingPenaltyQuotient; DecreaseBalance(state, slashedIndex, slashingPenalty); // Apply proposer and whistleblower rewards var proposerIndex = _beaconStateAccessor.GetBeaconProposerIndex(state); if (whistleblowerIndex == ValidatorIndex.None) { whistleblowerIndex = proposerIndex; } var whistleblowerReward = validator.EffectiveBalance / rewardsAndPenalties.WhistleblowerRewardQuotient; var proposerReward = whistleblowerReward / rewardsAndPenalties.ProposerRewardQuotient; IncreaseBalance(state, proposerIndex, proposerReward); IncreaseBalance(state, whistleblowerIndex, whistleblowerReward - proposerReward); }
// Run ``process_attester_slashing``, yielding: // - pre-state('pre') // - attester_slashing('attester_slashing') // - post-state('post'). //If ``valid == False``, run expecting ``AssertionError`` private void RunAttesterSlashingProcessing(IServiceProvider testServiceProvider, BeaconState state, AttesterSlashing attesterSlashing, bool expectValid) { ChainConstants chainConstants = testServiceProvider.GetService <ChainConstants>(); StateListLengths stateListLengths = testServiceProvider.GetService <IOptions <StateListLengths> >().Value; RewardsAndPenalties rewardsAndPenalties = testServiceProvider.GetService <IOptions <RewardsAndPenalties> >().Value; BeaconStateAccessor beaconStateAccessor = testServiceProvider.GetService <BeaconStateAccessor>(); BeaconStateTransition beaconStateTransition = testServiceProvider.GetService <BeaconStateTransition>(); if (!expectValid) { Should.Throw <Exception>(() => { beaconStateTransition.ProcessAttesterSlashing(state, attesterSlashing); }); return; } var slashedIndices = attesterSlashing.Attestation1.CustodyBit0Indices .Union(attesterSlashing.Attestation1.CustodyBit1Indices) .ToList(); ValidatorIndex proposerIndex = beaconStateAccessor.GetBeaconProposerIndex(state); Gwei preProposerBalance = TestState.GetBalance(state, proposerIndex); var preSlashings = slashedIndices.ToDictionary(x => x, x => TestState.GetBalance(state, x)); var preWithdrawableEpochs = slashedIndices.ToDictionary(x => x, x => state.Validators[(int)(ulong)x].WithdrawableEpoch); Gwei totalProposerRewards = preSlashings.Values.Aggregate(Gwei.Zero, (sum, x) => sum + x / rewardsAndPenalties.WhistleblowerRewardQuotient); // Process slashing beaconStateTransition.ProcessAttesterSlashing(state, attesterSlashing); foreach (ValidatorIndex slashedIndex in slashedIndices) { Console.WriteLine($"Checking index {slashedIndex}"); Epoch preWithdrawableEpoch = preWithdrawableEpochs[slashedIndex]; Validator slashedValidator = state.Validators[(int)(ulong)slashedIndex]; // Check Slashing slashedValidator.IsSlashed.ShouldBeTrue(); slashedValidator.ExitEpoch.ShouldBeLessThan(chainConstants.FarFutureEpoch); if (preWithdrawableEpoch < chainConstants.FarFutureEpoch) { ulong slashingsEpoch = beaconStateAccessor.GetCurrentEpoch(state) + stateListLengths.EpochsPerSlashingsVector; Epoch expectedWithdrawableEpoch = Epoch.Max(preWithdrawableEpoch, (Epoch)slashingsEpoch); slashedValidator.WithdrawableEpoch.ShouldBe(expectedWithdrawableEpoch); } else { slashedValidator.WithdrawableEpoch.ShouldBeLessThan(chainConstants.FarFutureEpoch); } Gwei preSlashing = preSlashings[slashedIndex]; Gwei slashedBalance = TestState.GetBalance(state, slashedIndex); slashedBalance.ShouldBeLessThan(preSlashing); } if (!slashedIndices.Contains(proposerIndex)) { // gained whistleblower reward Gwei expectedProposerBalance = preProposerBalance + totalProposerRewards; Gwei proposerBalance = TestState.GetBalance(state, proposerIndex); proposerBalance.ShouldBe(expectedProposerBalance); } else { // gained rewards for all slashings, which may include others. And only lost that of themselves. Gwei expectedProposerBalance = preProposerBalance + totalProposerRewards - (preSlashings[proposerIndex] / rewardsAndPenalties.MinimumSlashingPenaltyQuotient); Gwei proposerBalance = TestState.GetBalance(state, proposerIndex); proposerBalance.ShouldBe(expectedProposerBalance); } }