/// <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);
        }
        //    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);
            }
        }
Beispiel #3
0
        private static void ValidateConfigShouldHaveValues(MiscellaneousParameters miscellaneousParameters,
                                                           ForkChoiceConfiguration forkChoiceConfiguration, HonestValidatorConstants honestValidatorConstants,
                                                           GweiValues gweiValues, InitialValues initialValues, TimeParameters timeParameters,
                                                           StateListLengths stateListLengths, RewardsAndPenalties rewardsAndPenalties,
                                                           MaxOperationsPerBlock maxOperationsPerBlock, SignatureDomains signatureDomains)
        {
            miscellaneousParameters.ChurnLimitQuotient.ShouldNotBe(0uL);
            miscellaneousParameters.MaximumCommitteesPerSlot.ShouldNotBe(0uL);
            miscellaneousParameters.MaximumValidatorsPerCommittee.ShouldNotBe(0uL);
            miscellaneousParameters.MinimumGenesisActiveValidatorCount.ShouldNotBe(0);
            miscellaneousParameters.MinimumGenesisTime.ShouldNotBe(0uL);
            miscellaneousParameters.MinimumPerEpochChurnLimit.ShouldNotBe(0uL);
            miscellaneousParameters.ShuffleRoundCount.ShouldNotBe(0);
            miscellaneousParameters.TargetCommitteeSize.ShouldNotBe(0uL);

            forkChoiceConfiguration.SafeSlotsToUpdateJustified.ShouldNotBe(Slot.Zero);

            honestValidatorConstants.EpochsPerRandomSubnetSubscription.ShouldNotBe(Epoch.Zero);
            honestValidatorConstants.Eth1FollowDistance.ShouldNotBe(0uL);
            honestValidatorConstants.RandomSubnetsPerValidator.ShouldNotBe(0uL);
            honestValidatorConstants.SecondsPerEth1Block.ShouldNotBe(0uL);
            honestValidatorConstants.TargetAggregatorsPerCommittee.ShouldNotBe(0uL);


            gweiValues.EffectiveBalanceIncrement.ShouldNotBe(Gwei.Zero);
            gweiValues.EjectionBalance.ShouldNotBe(Gwei.Zero);
            gweiValues.MaximumEffectiveBalance.ShouldNotBe(Gwei.Zero);

            // actually should be zero
            initialValues.BlsWithdrawalPrefix.ShouldBe((byte)0);

            initialValues.GenesisForkVersion.ShouldBe(new ForkVersion(new byte[] { 0x00, 0x00, 0x00, 0x01 }));

            timeParameters.MaximumSeedLookahead.ShouldNotBe(Epoch.Zero);
            timeParameters.MinimumAttestationInclusionDelay.ShouldNotBe(Slot.Zero);
            timeParameters.MinimumGenesisDelay.ShouldNotBe(0u);
            timeParameters.MinimumEpochsToInactivityPenalty.ShouldNotBe(Epoch.Zero);
            timeParameters.MinimumSeedLookahead.ShouldNotBe(Epoch.Zero);
            timeParameters.MinimumValidatorWithdrawabilityDelay.ShouldNotBe(Epoch.Zero);
            timeParameters.PersistentCommitteePeriod.ShouldNotBe(Epoch.Zero);
            timeParameters.SecondsPerSlot.ShouldNotBe(0U);
            timeParameters.SlotsPerEpoch.ShouldNotBe(0U);
            timeParameters.SlotsPerEth1VotingPeriod.ShouldNotBe(0U);
            timeParameters.SlotsPerHistoricalRoot.ShouldNotBe(0U);

            stateListLengths.EpochsPerHistoricalVector.ShouldNotBe(0U);
            stateListLengths.EpochsPerSlashingsVector.ShouldNotBe(0U);
            stateListLengths.HistoricalRootsLimit.ShouldNotBe(0uL);
            stateListLengths.ValidatorRegistryLimit.ShouldNotBe(0uL);

            rewardsAndPenalties.BaseRewardFactor.ShouldNotBe(0uL);
            rewardsAndPenalties.InactivityPenaltyQuotient.ShouldNotBe(0uL);
            rewardsAndPenalties.MinimumSlashingPenaltyQuotient.ShouldNotBe(0uL);
            rewardsAndPenalties.ProposerRewardQuotient.ShouldNotBe(0uL);
            rewardsAndPenalties.WhistleblowerRewardQuotient.ShouldNotBe(0uL);

            maxOperationsPerBlock.MaximumAttestations.ShouldNotBe(0uL);
            maxOperationsPerBlock.MaximumAttesterSlashings.ShouldNotBe(0uL);
            maxOperationsPerBlock.MaximumDeposits.ShouldNotBe(0uL);
            maxOperationsPerBlock.MaximumProposerSlashings.ShouldNotBe(0uL);
            maxOperationsPerBlock.MaximumVoluntaryExits.ShouldNotBe(0uL);

            // actually should be zero
            signatureDomains.BeaconProposer.ShouldBe(default);