Ejemplo n.º 1
0
        public void ProcessSlashings(BeaconState state)
        {
            _logger.LogInformation(Event.ProcessSlashings, "Process epoch slashings state {BeaconState}", state);

            var currentEpoch = _beaconStateAccessor.GetCurrentEpoch(state);
            var totalBalance = _beaconStateAccessor.GetTotalActiveBalance(state);

            var targetEpoch = currentEpoch + new Epoch((ulong)_stateListLengthOptions.CurrentValue.EpochsPerSlashingsVector / 2);

            var totalSlashings = state.Slashings.Aggregate(Gwei.Zero, (accumulator, x) => accumulator + x);
            var minimumFactor  = Gwei.Min(totalSlashings * 3, totalBalance);

            for (var index = 0; index < state.Validators.Count; index++)
            {
                var validator = state.Validators[index];
                if (validator.IsSlashed && validator.WithdrawableEpoch == targetEpoch)
                {
                    var increment        = (ulong)_gweiValueOptions.CurrentValue.EffectiveBalanceIncrement; // # Factored out from penalty numerator to avoid uint64 overflow
                    var penaltyNumerator = (validator.EffectiveBalance / increment) * (ulong)minimumFactor;
                    var penalty          = (penaltyNumerator / (ulong)totalBalance) * increment;
                    var validatorIndex   = new ValidatorIndex((ulong)index);
                    _beaconStateMutator.DecreaseBalance(state, validatorIndex, penalty);
                }
            }
        }
Ejemplo n.º 2
0
        //    Run ``process_deposit``, yielding:
        //  - pre-state('pre')
        //  - deposit('deposit')
        //  - post-state('post').
        //If ``valid == False``, run expecting ``AssertionError``
        private void RunDepositProcessing(IServiceProvider testServiceProvider, BeaconState state, Deposit deposit, ValidatorIndex validatorIndex, bool expectValid, bool effective)
        {
            GweiValues            gweiValues            = testServiceProvider.GetService <IOptions <GweiValues> >().Value;
            BeaconStateTransition beaconStateTransition = testServiceProvider.GetService <BeaconStateTransition>();

            int  preValidatorCount = state.Validators.Count;
            Gwei preBalance        = Gwei.Zero;

            if ((int)(ulong)validatorIndex < preValidatorCount)
            {
                preBalance = TestState.GetBalance(state, validatorIndex);
            }

            if (!expectValid)
            {
                Should.Throw <Exception>(() =>
                {
                    beaconStateTransition.ProcessDeposit(state, deposit);
                });
                return;
            }

            beaconStateTransition.ProcessDeposit(state, deposit);

            if (!effective)
            {
                state.Validators.Count.ShouldBe(preValidatorCount);
                state.Balances.Count.ShouldBe(preValidatorCount);
                if ((int)(ulong)validatorIndex < preValidatorCount)
                {
                    Gwei balance = TestState.GetBalance(state, validatorIndex);
                    balance.ShouldBe(preBalance);
                }
            }
            else
            {
                if ((int)(ulong)validatorIndex < preValidatorCount)
                {
                    // top up
                    state.Validators.Count.ShouldBe(preValidatorCount);
                    state.Balances.Count.ShouldBe(preValidatorCount);
                }
                else
                {
                    // new validator
                    state.Validators.Count.ShouldBe(preValidatorCount + 1);
                    state.Balances.Count.ShouldBe(preValidatorCount + 1);
                }

                Gwei balance         = TestState.GetBalance(state, validatorIndex);
                Gwei expectedBalance = preBalance + deposit.Data.Item.Amount;
                balance.ShouldBe(expectedBalance);

                Gwei expectedEffectiveBalance = Gwei.Min(gweiValues.MaximumEffectiveBalance, expectedBalance);
                expectedEffectiveBalance -= expectedEffectiveBalance % gweiValues.EffectiveBalanceIncrement;
                state.Validators[(int)(ulong)validatorIndex].EffectiveBalance.ShouldBe(expectedEffectiveBalance);
            }

            state.Eth1DepositIndex.ShouldBe(state.Eth1Data.DepositCount);
        }
Ejemplo n.º 3
0
        public void ProcessFinalUpdates(BeaconState state)
        {
            _logger.LogInformation(Event.ProcessFinalUpdates, "Process epoch final updates state {BeaconState}", state);

            var timeParameters   = _timeParameterOptions.CurrentValue;
            var gweiValues       = _gweiValueOptions.CurrentValue;
            var stateListLengths = _stateListLengthOptions.CurrentValue;

            var currentEpoch = _beaconStateAccessor.GetCurrentEpoch(state);
            var nextEpoch    = currentEpoch + new Epoch(1);

            // Reset eth1 data votes
            var nextSlot = state.Slot + new Slot(1);

            if (nextSlot % timeParameters.SlotsPerEth1VotingPeriod == Slot.Zero)
            {
                state.ClearEth1DataVotes();
            }

            // Update effective balances with hysteresis
            var halfIncrement = gweiValues.EffectiveBalanceIncrement / 2;

            for (var index = 0; index < state.Validators.Count; index++)
            {
                var validator = state.Validators[index];
                var balance   = state.Balances[index];
                if (balance < validator.EffectiveBalance || (validator.EffectiveBalance + (halfIncrement * 3)) < balance)
                {
                    var roundedBalance   = balance - (balance % gweiValues.EffectiveBalanceIncrement);
                    var effectiveBalance = Gwei.Min(roundedBalance, gweiValues.MaximumEffectiveBalance);
                    validator.SetEffectiveBalance(effectiveBalance);
                }
            }

            // Reset slashings
            var slashingsIndex = nextEpoch % stateListLengths.EpochsPerSlashingsVector;

            state.SetSlashings(slashingsIndex, Gwei.Zero);

            // Set randao mix
            var randaoIndex = nextEpoch % stateListLengths.EpochsPerHistoricalVector;
            var randaoMix   = _beaconStateAccessor.GetRandaoMix(state, currentEpoch);

            state.SetRandaoMix(randaoIndex, randaoMix);

            // Set historical root accumulator
            var divisor = timeParameters.SlotsPerHistoricalRoot / timeParameters.SlotsPerEpoch;

            if ((ulong)nextEpoch % divisor == 0)
            {
                var historicalBatch = new HistoricalBatch(state.BlockRoots.ToArray(), state.StateRoots.ToArray());
                var historicalRoot  = historicalBatch.HashTreeRoot();
                state.AddHistoricalRoot(historicalRoot);
            }

            // Rotate current/previous epoch attestations
            state.SetPreviousEpochAttestations(state.CurrentEpochAttestations);
            state.SetCurrentEpochAttestations(new PendingAttestation[0]);
        }
Ejemplo n.º 4
0
        public BeaconState InitializeBeaconStateFromEth1(Bytes32 eth1BlockHash, ulong eth1Timestamp,
                                                         IList <Deposit> deposits)
        {
            if (_logger.IsInfo())
            {
                Log.InitializeBeaconState(_logger, eth1BlockHash, eth1Timestamp, deposits.Count, null);
            }

            InitialValues    initialValues    = _initialValueOptions.CurrentValue;
            GweiValues       gweiValues       = _gweiValueOptions.CurrentValue;
            TimeParameters   timeParameters   = _timeParameterOptions.CurrentValue;
            StateListLengths stateListLengths = _stateListLengthOptions.CurrentValue;

            Fork fork = new Fork(initialValues.GenesisForkVersion, initialValues.GenesisForkVersion,
                                 _chainConstants.GenesisEpoch);

            ulong genesisTime = eth1Timestamp - (eth1Timestamp % timeParameters.MinimumGenesisDelay)
                                + (2 * timeParameters.MinimumGenesisDelay);
            Eth1Data eth1Data = new Eth1Data(Root.Zero, (ulong)deposits.Count, eth1BlockHash);

            Root emptyBlockBodyRoot             = _cryptographyService.HashTreeRoot(BeaconBlockBody.Zero);
            BeaconBlockHeader latestBlockHeader = new BeaconBlockHeader(emptyBlockBodyRoot);

            Bytes32[] randaoMixes = Enumerable.Repeat(eth1BlockHash, (int)stateListLengths.EpochsPerHistoricalVector)
                                    .ToArray();

            BeaconState state = new BeaconState(genesisTime, fork, eth1Data, latestBlockHeader, randaoMixes,
                                                timeParameters.SlotsPerHistoricalRoot, stateListLengths.EpochsPerHistoricalVector,
                                                stateListLengths.EpochsPerSlashingsVector, _chainConstants.JustificationBitsLength);

            // Process deposits
            List <DepositData> depositDataList = new List <DepositData>();

            foreach (Deposit deposit in deposits)
            {
                depositDataList.Add(deposit.Data);
                Root depositRoot = _cryptographyService.HashTreeRoot(depositDataList);
                state.Eth1Data.SetDepositRoot(depositRoot);
                _beaconStateTransition.ProcessDeposit(state, deposit);
            }

            // Process activations
            for (int validatorIndex = 0; validatorIndex < state.Validators.Count; validatorIndex++)
            {
                Validator validator        = state.Validators[validatorIndex];
                Gwei      balance          = state.Balances[validatorIndex];
                Gwei      effectiveBalance = Gwei.Min(balance - (balance % gweiValues.EffectiveBalanceIncrement),
                                                      gweiValues.MaximumEffectiveBalance);
                validator.SetEffectiveBalance(effectiveBalance);
                if (validator.EffectiveBalance == gweiValues.MaximumEffectiveBalance)
                {
                    validator.SetEligible(_chainConstants.GenesisEpoch);
                    validator.SetActive(_chainConstants.GenesisEpoch);
                }
            }

            return(state);
        }
Ejemplo n.º 5
0
        public void ProcessDeposit(BeaconState state, Deposit deposit)
        {
            _logger.LogInformation(Event.ProcessDeposit, "Process block operation deposit {Deposit} for state {BeaconState}.", deposit, state);

            var gweiValues = _gweiValueOptions.CurrentValue;

            // Verify the Merkle branch
            var isValid = _beaconChainUtility.IsValidMerkleBranch(
                deposit.Data.HashTreeRoot(),
                deposit.Proof,
                _chainConstants.DepositContractTreeDepth + 1, // Add 1 for the 'List' length mix-in
                state.Eth1DepositIndex,
                state.Eth1Data.DepositRoot);

            if (!isValid)
            {
                throw new Exception($"Invalid Merle branch for deposit for validator poublic key {deposit.Data.PublicKey}");
            }

            // Deposits must be processed in order
            state.IncreaseEth1DepositIndex();

            var publicKey           = deposit.Data.PublicKey;
            var amount              = deposit.Data.Amount;
            var validatorPublicKeys = state.Validators.Select(x => x.PublicKey).ToList();

            if (!validatorPublicKeys.Contains(publicKey))
            {
                // Verify the deposit signature (proof of possession) for new validators
                // Note: The deposit contract does not check signatures.
                // Note: Deposits are valid across forks, thus the deposit domain is retrieved directly from 'computer_domain'.

                var domain = _beaconChainUtility.ComputeDomain(_signatureDomainOptions.CurrentValue.Deposit);
                if (!_cryptographyService.BlsVerify(publicKey, deposit.Data.SigningRoot(), deposit.Data.Signature, domain))
                {
                    return;
                }

                var effectiveBalance = Gwei.Min(amount - (amount % gweiValues.EffectiveBalanceIncrement), gweiValues.MaximumEffectiveBalance);
                var newValidator     = new Validator(
                    publicKey,
                    deposit.Data.WithdrawalCredentials,
                    effectiveBalance
                    ,
                    _chainConstants.FarFutureEpoch,
                    _chainConstants.FarFutureEpoch,
                    _chainConstants.FarFutureEpoch,
                    _chainConstants.FarFutureEpoch);
                state.AddValidatorWithBalance(newValidator, amount);
            }
            else
            {
                var index = (ValidatorIndex)(ulong)validatorPublicKeys.IndexOf(publicKey);
                _beaconStateMutator.IncreaseBalance(state, index, amount);
            }
        }
Ejemplo n.º 6
0
        public BeaconState InitializeBeaconStateFromEth1(Hash32 eth1BlockHash, ulong eth1Timestamp, IEnumerable <Deposit> deposits)
        {
            _logger.LogDebug(Event.InitializeBeaconState, "Initialise beacon state from ETH1 block {Eth1BlockHash}, time {Eth1Timestamp}, with {DepositCount} deposits.", eth1BlockHash, eth1Timestamp, deposits.Count());

            var gweiValues       = _gweiValueOptions.CurrentValue;
            var initialValues    = _initialValueOptions.CurrentValue;
            var timeParameters   = _timeParameterOptions.CurrentValue;
            var stateListLengths = _stateListLengthOptions.CurrentValue;

            var genesisTime = eth1Timestamp - (eth1Timestamp % _chainConstants.SecondsPerDay)
                              + (2 * _chainConstants.SecondsPerDay);
            var eth1Data          = new Eth1Data((ulong)deposits.Count(), eth1BlockHash);
            var emptyBlockBody    = new BeaconBlockBody();
            var latestBlockHeader = new BeaconBlockHeader(emptyBlockBody.HashTreeRoot(_miscellaneousParameterOptions.CurrentValue, _maxOperationsPerBlockOptions.CurrentValue));
            var state             = new BeaconState(genesisTime, 0, eth1Data, latestBlockHeader, timeParameters.SlotsPerHistoricalRoot, stateListLengths.EpochsPerHistoricalVector, stateListLengths.EpochsPerSlashingsVector, _chainConstants.JustificationBitsLength);

            // Process deposits
            var depositDataList = new List <DepositData>();

            foreach (var deposit in deposits)
            {
                depositDataList.Add(deposit.Data);
                var depositRoot = depositDataList.HashTreeRoot(_chainConstants.MaximumDepositContracts);
                state.Eth1Data.SetDepositRoot(depositRoot);
                _beaconStateTransition.ProcessDeposit(state, deposit);
            }

            // Process activations
            for (var validatorIndex = 0; validatorIndex < state.Validators.Count; validatorIndex++)
            {
                var validator        = state.Validators[validatorIndex];
                var balance          = state.Balances[validatorIndex];
                var effectiveBalance = Gwei.Min(balance - (balance % gweiValues.EffectiveBalanceIncrement), gweiValues.MaximumEffectiveBalance);
                validator.SetEffectiveBalance(effectiveBalance);
                if (validator.EffectiveBalance == gweiValues.MaximumEffectiveBalance)
                {
                    validator.SetEligible(initialValues.GenesisEpoch);
                    validator.SetActive(initialValues.GenesisEpoch);
                }
            }

            return(state);
        }
Ejemplo n.º 7
0
        public static Validator BuildMockValidator(ChainConstants chainConstants, InitialValues initialValues, GweiValues gweiValues, TimeParameters timeParameters, ulong validatorIndex, Gwei balance)
        {
            var publicKeys = TestKeys.PublicKeys(timeParameters).ToArray();
            var publicKey  = publicKeys[validatorIndex];
            // insecurely use pubkey as withdrawal key if no credentials provided
            var withdrawalCredentialBytes = TestSecurity.Hash(publicKey.AsSpan());

            withdrawalCredentialBytes[0] = initialValues.BlsWithdrawalPrefix;
            var withdrawalCredentials = new Bytes32(withdrawalCredentialBytes);

            var validator = new Validator(
                publicKey,
                withdrawalCredentials,
                Gwei.Min(balance - balance % gweiValues.EffectiveBalanceIncrement, gweiValues.MaximumEffectiveBalance),
                false,
                chainConstants.FarFutureEpoch,
                chainConstants.FarFutureEpoch,
                chainConstants.FarFutureEpoch,
                chainConstants.FarFutureEpoch);

            return(validator);
        }