Exemple #1
0
        public async Task <Gwei> GetLatestAttestingBalanceAsync(IStore store, Hash32 root)
        {
            // NOTE: This method should probably live in IStore, for various efficient implementations.

            Checkpoint             justifiedCheckpoint = store.JustifiedCheckpoint;
            BeaconState            state         = (await store.GetCheckpointStateAsync(justifiedCheckpoint, true).ConfigureAwait(false)) !;
            Epoch                  currentEpoch  = _beaconStateAccessor.GetCurrentEpoch(state);
            IList <ValidatorIndex> activeIndexes = _beaconStateAccessor.GetActiveValidatorIndices(state, currentEpoch);
            BeaconBlock            rootBlock     = await store.GetBlockAsync(root).ConfigureAwait(false);

            Slot rootSlot = rootBlock !.Slot;
            Gwei balance  = Gwei.Zero;

            foreach (ValidatorIndex index in activeIndexes)
            {
                LatestMessage?latestMessage = await store.GetLatestMessageAsync(index, false);

                if (latestMessage != null)
                {
                    Hash32 ancestor = await GetAncestorAsync(store, latestMessage.Root, rootSlot);

                    if (ancestor == root)
                    {
                        Validator validator = state.Validators[(int)index];
                        balance += validator.EffectiveBalance;
                    }
                }
            }

            return(balance);
        }
Exemple #2
0
        private static Gwei DecodeGwei(Span <byte> span, ref int offset)
        {
            Gwei gwei = new Gwei(BinaryPrimitives.ReadUInt64LittleEndian(span.Slice(offset)));

            offset += Gwei.SszLength;
            return(gwei);
        }
Exemple #3
0
        public async Task <Hash32> GetHeadAsync(IStore store)
        {
            // NOTE: This method should probably live in a separate object, for different implementations, possibly part of Store (for efficiency).

            // Execute the LMD-GHOST fork choice
            Hash32 head          = store.JustifiedCheckpoint.Root;
            Slot   justifiedSlot = _beaconChainUtility.ComputeStartSlotOfEpoch(store.JustifiedCheckpoint.Epoch);

            while (true)
            {
                List <Tuple <Hash32, Gwei> > childKeysWithBalances = new List <Tuple <Hash32, Gwei> >();
                await foreach (Hash32 childKey in store.GetChildKeysAfterSlotAsync(head, justifiedSlot)
                               .ConfigureAwait(false))
                {
                    Gwei balance = await GetLatestAttestingBalanceAsync(store, childKey).ConfigureAwait(false);

                    childKeysWithBalances.Add(Tuple.Create(childKey, balance));
                }
                if (childKeysWithBalances.Count == 0)
                {
                    return(head);
                }

                head = childKeysWithBalances
                       .OrderByDescending(x => x.Item2)
                       .ThenByDescending(x => x.Item1)
                       .Select(x => x.Item1)
                       .First();
            }
        }
        /// <summary>
        /// Increase the validator balance at index ``index`` by ``delta``.
        /// </summary>
        public void IncreaseBalance(BeaconState state, ValidatorIndex index, Gwei delta)
        {
            Gwei balance    = state.Balances[(int)index];
            Gwei newBalance = balance + delta;

            state.SetBalance(index, newBalance);
        }
 public DepositData(BlsPublicKey publicKey, Bytes32 withdrawalCredentials, Gwei amount, BlsSignature signature)
 {
     PublicKey             = publicKey;
     WithdrawalCredentials = withdrawalCredentials;
     Amount    = amount;
     Signature = signature; // Signing over DepositMessage
 }
Exemple #6
0
 public DepositData(BlsPublicKey publicKey, Hash32 withdrawalCredentials, Gwei amount)
 {
     PublicKey             = publicKey;
     WithdrawalCredentials = withdrawalCredentials;
     Amount    = amount;
     Signature = new BlsSignature();
 }
Exemple #7
0
        /// <summary>
        /// Return from ``indices`` a random index sampled by effective balance.
        /// </summary>
        public ValidatorIndex ComputeProposerIndex(BeaconState state, IList <ValidatorIndex> indices, Bytes32 seed)
        {
            if (!indices.Any())
            {
                throw new ArgumentException("Indices can not be empty", nameof(indices));
            }

            ulong          indexCount       = (ulong)indices.Count;
            ValidatorIndex index            = 0UL;
            Span <byte>    randomInputBytes = stackalloc byte[40];

            seed.AsSpan().CopyTo(randomInputBytes);
            while (true)
            {
                ValidatorIndex initialValidatorIndex = (ValidatorIndex)(index % indexCount);
                ValidatorIndex shuffledIndex         = ComputeShuffledIndex(initialValidatorIndex, indexCount, seed);
                ValidatorIndex candidateIndex        = indices[(int)shuffledIndex];

                BinaryPrimitives.WriteUInt64LittleEndian(randomInputBytes.Slice(32), index / 32);
                Bytes32 randomHash = _cryptographyService.Hash(randomInputBytes);
                byte    random     = randomHash.AsSpan()[(int)(index % 32)];

                Gwei effectiveBalance = state.Validators[(int)candidateIndex].EffectiveBalance;
                if ((effectiveBalance * byte.MaxValue) >=
                    (_gweiValueOptions.CurrentValue.MaximumEffectiveBalance * random))
                {
                    return(candidateIndex);
                }

                index++;
            }
        }
Exemple #8
0
 public EffectiveBalanceCase(Gwei preEffective, Gwei balance, Gwei postEffective, string name)
 {
     PreEffective  = preEffective;
     Balance       = balance;
     PostEffective = postEffective;
     Name          = name;
 }
Exemple #9
0
        public async Task <Gwei> GetLatestAttestingBalanceAsync(IStore store, Root root)
        {
            Checkpoint             justifiedCheckpoint = store.JustifiedCheckpoint;
            BeaconState            state         = (await store.GetCheckpointStateAsync(justifiedCheckpoint, true).ConfigureAwait(false)) !;
            Epoch                  currentEpoch  = _beaconStateAccessor.GetCurrentEpoch(state);
            IList <ValidatorIndex> activeIndexes = _beaconStateAccessor.GetActiveValidatorIndices(state, currentEpoch);
            SignedBeaconBlock      rootBlock     = await store.GetSignedBlockAsync(root).ConfigureAwait(false);

            Slot rootSlot = rootBlock !.Message.Slot;
            Gwei balance  = Gwei.Zero;

            foreach (ValidatorIndex index in activeIndexes)
            {
                LatestMessage?latestMessage = await store.GetLatestMessageAsync(index, false);

                if (latestMessage != null)
                {
                    Root ancestor = await store.GetAncestorAsync(latestMessage.Root, rootSlot);

                    if (ancestor == root)
                    {
                        Validator validator = state.Validators[(int)index];
                        balance += validator.EffectiveBalance;
                    }
                }
            }

            return(balance);
        }
Exemple #10
0
        public Gwei GetLatestAttestingBalance(IStore store, Hash32 root)
        {
            if (!store.TryGetCheckpointState(store.JustifiedCheckpoint, out var storedState))
            {
                throw new Exception($"Not able to get checkpoint state {store.JustifiedCheckpoint}");
            }

            var state         = storedState !;
            var currentEpoch  = _beaconStateAccessor.GetCurrentEpoch(state);
            var activeIndexes = _beaconStateAccessor.GetActiveValidatorIndices(state, currentEpoch);

            if (!store.TryGetBlock(root, out var rootBlock))
            {
                throw new Exception($"Not ble to find block {root}");
            }

            Slot rootSlot = rootBlock !.Slot;
            Gwei balance  = Gwei.Zero;

            foreach (ValidatorIndex index in activeIndexes)
            {
                if (store.TryGetLatestMessage(index, out var latestMessage))
                {
                    var ancestor = GetAncestor(store, latestMessage !.Root, rootSlot);
                    if (ancestor == root)
                    {
                        var validator = state.Validators[(int)index];
                        balance += validator.EffectiveBalance;
                    }
                }
            }

            return(balance);
        }
Exemple #11
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)
        {
            var gweiValues            = testServiceProvider.GetService <IOptions <GweiValues> >().Value;
            var beaconStateTransition = testServiceProvider.GetService <BeaconStateTransition>();

            var preValidatorCount = state.Validators.Count;
            var 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)
                {
                    var 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);
                }

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

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

            state.Eth1DepositIndex.ShouldBe(state.Eth1Data.DepositCount);
        }
Exemple #12
0
        public void MaximumPenalties()
        {
            // Arrange
            IServiceProvider testServiceProvider = TestSystem.BuildTestServiceProvider();
            BeaconState      state = TestState.PrepareTestState(testServiceProvider);

            StateListLengths    stateListLengths    = testServiceProvider.GetService <IOptions <StateListLengths> >().Value;
            BeaconStateAccessor beaconStateAccessor = testServiceProvider.GetService <BeaconStateAccessor>();

            int   slashedCount = (state.Validators.Count / 3) + 1;
            Epoch currentEpoch = beaconStateAccessor.GetCurrentEpoch(state);
            Epoch outEpoch     = currentEpoch + new Epoch((ulong)stateListLengths.EpochsPerSlashingsVector / 2);

            var slashedIndices = Enumerable.Range(0, slashedCount).ToList();

            SlashValidators(testServiceProvider, state, slashedIndices, Enumerable.Repeat(outEpoch, slashedCount));

            Gwei totalBalance   = beaconStateAccessor.GetTotalActiveBalance(state);
            Gwei totalPenalties = state.Slashings.Aggregate(Gwei.Zero, (accumulator, x) => accumulator + x);

            (totalBalance / 3).ShouldBeLessThanOrEqualTo(totalPenalties);

            // Act
            RunProcessSlashings(testServiceProvider, state);

            // Assert
            foreach (int index in slashedIndices)
            {
                state.Balances[index].ShouldBe(Gwei.Zero, $"Incorrect balance {index}");
            }
        }
        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]);
        }
Exemple #14
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);
            }
        }
Exemple #16
0
        private DepositData BuildAndSignDepositData(ulong validatorIndex, Gwei amount, SignatureDomains signatureDomains)
        {
            InitialValues initialValues = _initialValueOptions.CurrentValue;

            byte[] privateKey = GeneratePrivateKey(validatorIndex);

            // Public Key
            BLSParameters blsParameters = new BLSParameters
            {
                PrivateKey = privateKey
            };

            using BLS bls = BLS.Create(blsParameters);
            byte[] publicKeyBytes = new byte[BlsPublicKey.Length];
            bls.TryExportBlsPublicKey(publicKeyBytes, out int publicKeyBytesWritten);
            BlsPublicKey publicKey = new BlsPublicKey(publicKeyBytes);

            // Withdrawal Credentials
            Bytes32 withdrawalCredentials = _crypto.Hash(publicKey.AsSpan());

            withdrawalCredentials.Unwrap()[0] = initialValues.BlsWithdrawalPrefix;

            // Build deposit data
            DepositData depositData = new DepositData(publicKey, withdrawalCredentials, amount, BlsSignature.Zero);

            // Sign deposit data
            Domain         domain         = _beaconChainUtility.ComputeDomain(signatureDomains.Deposit);
            DepositMessage depositMessage = new DepositMessage(
                depositData.PublicKey,
                depositData.WithdrawalCredentials,
                depositData.Amount);

            Root depositMessageRoot     = _crypto.HashTreeRoot(depositMessage);
            Root depositDataSigningRoot = _beaconChainUtility.ComputeSigningRoot(depositMessageRoot, domain);

            byte[] signatureBytes = new byte[96];
            bls.TrySignData(depositDataSigningRoot.AsSpan(), signatureBytes, out int bytesWritten);

            BlsSignature depositDataSignature = new BlsSignature(signatureBytes);

            depositData.SetSignature(depositDataSignature);

            if (_logger.IsEnabled(LogLevel.Debug))
            {
                LogDebug.QuickStartAddValidator(_logger, validatorIndex, publicKey.ToString().Substring(0, 12),
                                                null);
            }

            return(depositData);
        }
        /// <summary>
        /// Decrease the validator balance at index ``index`` by ``delta``, with underflow protection.
        /// </summary>
        public void DecreaseBalance(BeaconState state, ValidatorIndex index, Gwei delta)
        {
            Gwei balance = state.Balances[(int)index];

            if (delta > balance)
            {
                state.SetBalance(index, Gwei.Zero);
            }
            else
            {
                Gwei newBalance = balance - delta;
                state.SetBalance(index, newBalance);
            }
        }
        public static DepositData DecodeDepositData(Span <byte> span)
        {
            if (span.Length != Ssz.DepositDataLength)
            {
                ThrowSourceLength <DepositData>(span.Length, Ssz.DepositDataLength);
            }
            int          offset                = 0;
            BlsPublicKey publicKey             = DecodeBlsPublicKey(span, ref offset);
            Hash32       withdrawalCredentials = DecodeSha256(span, ref offset);
            Gwei         amount                = DecodeGwei(span, ref offset);
            BlsSignature signature             = DecodeBlsSignature(span, ref offset);
            DepositData  container             = new DepositData(publicKey, withdrawalCredentials, amount, signature);

            return(container);
        }
Exemple #19
0
        /// <summary>
        /// Return the combined effective balance of the ``indices``. (1 Gwei minimum to avoid divisions by zero.)
        /// </summary>
        public Gwei GetTotalBalance(BeaconState state, IEnumerable <ValidatorIndex> validatorIndices)
        {
            Gwei total = Gwei.Zero;

            foreach (ValidatorIndex index in validatorIndices)
            {
                Validator validator = state.Validators[(int)index];
                Gwei      balance   = validator.EffectiveBalance;
                total += balance;
            }
            if (total == Gwei.Zero)
            {
                return(new Gwei(1));
            }
            return(total);
        }
        /// <summary>
        /// Return the combined effective balance of the ``indices``. (1 Gwei minimum to avoid divisions by zero.)
        /// </summary>
        public Gwei GetTotalBalance(BeaconState state, IEnumerable <ValidatorIndex> validatorIndices)
        {
            var total = new Gwei(0);

            foreach (var index in validatorIndices)
            {
                var validator = state.Validators[(int)(ulong)index];
                var balance   = validator.EffectiveBalance;
                total += balance;
            }
            if (total == new Gwei(0))
            {
                return(new Gwei(1));
            }
            return(total);
        }
Exemple #21
0
        public void NewDepositUnderMax()
        {
            // Arrange
            IServiceProvider testServiceProvider = TestSystem.BuildTestServiceProvider();
            BeaconState      state = TestState.PrepareTestState(testServiceProvider);

            // fresh deposit = next validator index = validator appended to registry
            ValidatorIndex validatorIndex = new ValidatorIndex((ulong)state.Validators.Count);

            // effective balance will be 1 EFFECTIVE_BALANCE_INCREMENT smaller because of this small decrement.
            GweiValues gweiValues = testServiceProvider.GetService <IOptions <GweiValues> >().Value;
            Gwei       amount     = gweiValues.MaximumEffectiveBalance - new Gwei(1);

            Deposit deposit = TestDeposit.PrepareStateAndDeposit(testServiceProvider, state, validatorIndex, amount, Bytes32.Zero, signed: true);

            RunDepositProcessing(testServiceProvider, state, deposit, validatorIndex, expectValid: true, effective: true);
        }
Exemple #22
0
        public async Task <Root> GetHeadAsync(IStore store)
        {
            // NOTE: These functions have been moved here, instead of ForkChoice, because some of them may benefit
            // from direct looking in the storage mechanism (e.g. database) or have other ways to optimise based on
            // the actual storage used.

            // TODO: Several different implementations provided in spec, for efficiency
            // TODO: Also, should cache, i.e. will only change if store is updated (so should be easy to cache if in store)

            // Get filtered block tree that only includes viable branches
            IDictionary <Root, BeaconBlock> blocks = await GetFilteredBlockTreeAsync(store).ConfigureAwait(false);

            // Latest Message Driven - Greedy Heaviest Observed Subtree
            // Fresh Message Driven

            // Execute the LMD-GHOST fork choice
            Root head          = store.JustifiedCheckpoint.Root;
            Slot justifiedSlot = _beaconChainUtility.ComputeStartSlotOfEpoch(store.JustifiedCheckpoint.Epoch);

            while (true)
            {
                List <Tuple <Root, Gwei> > childKeysWithBalances = new List <Tuple <Root, Gwei> >();
                foreach (KeyValuePair <Root, BeaconBlock> kvp in blocks)
                {
                    if (kvp.Value.ParentRoot.Equals(head) && kvp.Value.Slot > justifiedSlot)
                    {
                        Gwei balance = await GetLatestAttestingBalanceAsync(store, kvp.Key).ConfigureAwait(false);

                        childKeysWithBalances.Add(Tuple.Create(kvp.Key, balance));
                    }
                }

                if (childKeysWithBalances.Count == 0)
                {
                    return(head);
                }

                // Sort by latest attesting balance with ties broken lexicographically
                head = childKeysWithBalances
                       .OrderByDescending(x => x.Item2)
                       .ThenByDescending(x => x.Item1)
                       .Select(x => x.Item1)
                       .First();
            }
        }
Exemple #23
0
 public Validator(
     BlsPublicKey publicKey,
     Hash32 withdrawalCredentials,
     Gwei effectiveBalance,
     //bool slashed,
     Epoch activationEligibilityEpoch,
     Epoch activationEpoch,
     Epoch exitEpoch,
     Epoch withdrawableEpoch)
 {
     PublicKey                  = publicKey;
     WithdrawalCredentials      = withdrawalCredentials;
     EffectiveBalance           = effectiveBalance;
     ActivationEligibilityEpoch = activationEligibilityEpoch;
     ActivationEpoch            = activationEpoch;
     ExitEpoch                  = exitEpoch;
     WithdrawableEpoch          = withdrawableEpoch;
 }
Exemple #24
0
        public static Gwei[] DecodeGweis(Span <byte> span)
        {
            if (span.Length == 0)
            {
                return(Array.Empty <Gwei>());
            }

            int count = span.Length / Ssz.GweiLength;

            Gwei[] result = new Gwei[count];
            for (int i = 0; i < count; i++)
            {
                Span <byte> current = span.Slice(i * Ssz.GweiLength, Ssz.GweiLength);
                result[i] = DecodeGwei(current);
            }

            return(result);
        }
Exemple #25
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);
        }
Exemple #26
0
        public static Validator DecodeValidator(Span <byte> span)
        {
            if (span.Length != Ssz.ValidatorLength)
            {
                ThrowSourceLength <Validator>(span.Length, Ssz.ValidatorLength);
            }
            int          offset                     = 0;
            BlsPublicKey publicKey                  = DecodeBlsPublicKey(span, ref offset);
            Bytes32      withdrawalCredentials      = DecodeBytes32(span, ref offset);
            Gwei         effectiveBalance           = DecodeGwei(span, ref offset);
            bool         isSlashed                  = DecodeBool(span, ref offset);
            Epoch        activationEligibilityEpoch = DecodeEpoch(span, ref offset);
            Epoch        activationEpoch            = DecodeEpoch(span, ref offset);
            Epoch        exitEpoch                  = DecodeEpoch(span, ref offset);
            Epoch        withdrawableEpoch          = DecodeEpoch(span, ref offset);
            Validator    container                  = new Validator(publicKey, withdrawalCredentials, effectiveBalance, isSlashed,
                                                                    activationEligibilityEpoch, activationEpoch, exitEpoch, withdrawableEpoch);

            return(container);
        }
Exemple #27
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);
        }
Exemple #28
0
        private void SlashValidators(IServiceProvider testServiceProvider, BeaconState state, IEnumerable <int> indices, IEnumerable <Epoch> outEpochs)
        {
            StateListLengths stateListLengths = testServiceProvider.GetService <IOptions <StateListLengths> >().Value;

            BeaconStateAccessor beaconStateAccessor = testServiceProvider.GetService <BeaconStateAccessor>();
            BeaconStateMutator  beaconStateMutator  = testServiceProvider.GetService <BeaconStateMutator>();

            Gwei totalSlashedBalance = Gwei.Zero;
            var  items = indices.Zip(outEpochs, (index, outEpoch) => new { index, outEpoch });

            foreach (var item in items)
            {
                Validator validator = state.Validators[item.index];
                validator.SetSlashed();
                beaconStateMutator.InitiateValidatorExit(state, new ValidatorIndex((ulong)item.index));
                validator.SetWithdrawableEpoch(item.outEpoch);
                totalSlashedBalance += validator.EffectiveBalance;
            }

            Epoch currentEpoch   = beaconStateAccessor.GetCurrentEpoch(state);
            Epoch slashingsIndex = (Epoch)(currentEpoch % stateListLengths.EpochsPerSlashingsVector);

            state.SetSlashings(slashingsIndex, totalSlashedBalance);
        }
Exemple #29
0
        private Gwei GetLatestAttestingBalance(Hash32 root)
        {
            var state = CheckpointStates[JustifiedCheckpoint];
            //var currentEpoch = GetCurrentEpoch(state);
            //var activeIndexes = GetActiveValidatorIndices(state, currentEpoch);
            var rootSlot = Blocks[root].Slot;
            var balance  = new Gwei(0);

            /*
             * foreach (var index in activeIndexes)
             * {
             *  if (LatestMessages.Contains(index))
             *  {
             *      var latestMessage = LatestMessages[index];
             *      var ancestor = GetAncestor(latestMessage.Root, rootSlot);
             *      if (ancestor == root)
             *      {
             *          balance += state.Validators[index].EffectiveBalance;
             *      }
             *  }
             * }
             */
            return(balance);
        }
        /// <summary>
        /// Slash the validator with index ``slashed_index``.
        /// </summary>
        public void SlashValidator(BeaconState state, ValidatorIndex slashedIndex, ValidatorIndex whistleblowerIndex)
        {
            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);

            if (whistleblowerIndex == ValidatorIndex.None)
            {
                whistleblowerIndex = proposerIndex;
            }
            Gwei whistleblowerReward = validator.EffectiveBalance / rewardsAndPenalties.WhistleblowerRewardQuotient;
            Gwei proposerReward      = whistleblowerReward / rewardsAndPenalties.ProposerRewardQuotient;

            IncreaseBalance(state, proposerIndex, proposerReward);
            IncreaseBalance(state, whistleblowerIndex, whistleblowerReward - proposerReward);
        }