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); } } }
// 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); }
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]); }
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); }
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); } }
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); }
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); }