Example #1
0
        public Slot ComputeSlotsSinceEpochStart(Slot slot)
        {
            Epoch epoch     = _beaconChainUtility.ComputeEpochAtSlot(slot);
            Slot  startSlot = _beaconChainUtility.ComputeStartSlotOfEpoch(epoch);

            return(slot - startSlot);
        }
Example #2
0
        /// <summary>
        ///     Return the committee assignment in the ``epoch`` for ``validator_index``.
        ///     ``assignment`` returned is a tuple of the following form:
        ///     * ``assignment[0]`` is the list of validators in the committee
        ///     * ``assignment[1]`` is the index to which the committee is assigned
        ///     * ``assignment[2]`` is the slot at which the committee is assigned
        ///     Return None if no assignment.
        /// </summary>
        public CommitteeAssignment GetCommitteeAssignment(BeaconState state, Epoch epoch, ValidatorIndex validatorIndex)
        {
            Epoch nextEpoch = _beaconStateAccessor.GetCurrentEpoch(state) + Epoch.One;

            if (epoch > nextEpoch)
            {
                throw new ArgumentOutOfRangeException(nameof(epoch), epoch,
                                                      $"Committee epoch cannot be greater than next epoch {nextEpoch}.");
            }

            TimeParameters timeParameters = _timeParameterOptions.CurrentValue;
            Slot           startSlot      = _beaconChainUtility.ComputeStartSlotOfEpoch(epoch);
            ulong          endSlot        = startSlot + timeParameters.SlotsPerEpoch;

            for (Slot slot = startSlot; slot < endSlot; slot += Slot.One)
            {
                ulong committeeCount = _beaconStateAccessor.GetCommitteeCountAtSlot(state, slot);
                for (CommitteeIndex index = CommitteeIndex.Zero;
                     index < new CommitteeIndex(committeeCount);
                     index += CommitteeIndex.One)
                {
                    IReadOnlyList <ValidatorIndex> committee =
                        _beaconStateAccessor.GetBeaconCommittee(state, slot, index);
                    if (committee.Contains(validatorIndex))
                    {
                        CommitteeAssignment committeeAssignment = new CommitteeAssignment(committee, index, slot);
                        return(committeeAssignment);
                    }
                }
            }

            return(CommitteeAssignment.None);
        }
        private async Task HandlePeerStatus(string peerId, PeeringStatus peerPeeringStatus, Root headRoot,
                                            BeaconState beaconState)
        {
            // if not valid, "immediately disconnect from one another following the handshake"
            bool isValidPeer = await IsValidPeerStatus(peerId, peerPeeringStatus, headRoot, beaconState)
                               .ConfigureAwait(false);

            if (!isValidPeer)
            {
                await _networkPeering.DisconnectPeerAsync(peerId).ConfigureAwait(false);

                return;
            }

            // check if we should request blocks
            var isPeerAhead = IsPeerAhead(peerPeeringStatus, beaconState);

            if (isPeerAhead)
            {
                // In theory, our chain since finalized checkpoint could be wrong
                // However it may be more efficient to check if our head is correct and sync from there,
                // or use the step option to sample blocks and find where we diverge.
                Slot finalizedSlot = _beaconChainUtility.ComputeStartSlotOfEpoch(beaconState.FinalizedCheckpoint.Epoch);

                if (_logger.IsInfo())
                {
                    Log.RequestingBlocksFromAheadPeer(_logger, peerId, finalizedSlot, peerPeeringStatus.HeadRoot,
                                                      peerPeeringStatus.HeadSlot, null);
                }

                // TODO: Need more sophistication, like Eth1; as peers are discovered, just put into a pool,
                // then, when need for sync determined, select the best peer(s) to use.

                await _networkPeering.RequestBlocksAsync(peerId, peerPeeringStatus.HeadRoot, finalizedSlot,
                                                         peerPeeringStatus.HeadSlot);
            }
            else
            {
                if (_logger.IsDebug())
                {
                    LogDebug.PeerBehind(_logger, peerId, peerPeeringStatus.FinalizedEpoch, peerPeeringStatus.HeadRoot,
                                        peerPeeringStatus.HeadSlot, null);
                }
            }
        }
        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();
            }
        }
        /// <summary>
        /// Return the block root at the start of a recent ``epoch``.
        /// </summary>
        public Root GetBlockRoot(BeaconState state, Epoch epoch)
        {
            Slot startSlot = _beaconChainUtility.ComputeStartSlotOfEpoch(epoch);

            return(GetBlockRootAtSlot(state, startSlot));
        }
Example #6
0
        private static AttestationData BuildAttestationData(IServiceProvider testServiceProvider, BeaconState state, Slot slot, CommitteeIndex index)
        {
            IBeaconChainUtility beaconChainUtility  = testServiceProvider.GetService <IBeaconChainUtility>();
            BeaconStateAccessor beaconStateAccessor = testServiceProvider.GetService <BeaconStateAccessor>();

            if (state.Slot > slot)
            {
                throw new ArgumentOutOfRangeException(nameof(slot), slot, $"Slot cannot be greater than state slot {state.Slot}.");
            }

            Root blockRoot;

            if (slot == state.Slot)
            {
                BeaconBlock nextBlock = TestBlock.BuildEmptyBlockForNextSlot(testServiceProvider, state, BlsSignature.Zero);
                blockRoot = nextBlock.ParentRoot;
            }
            else
            {
                blockRoot = beaconStateAccessor.GetBlockRootAtSlot(state, slot);
            }

            Root  epochBoundaryRoot;
            Epoch currentEpoch          = beaconStateAccessor.GetCurrentEpoch(state);
            Slot  currentEpochStartSlot = beaconChainUtility.ComputeStartSlotOfEpoch(currentEpoch);

            if (slot < currentEpochStartSlot)
            {
                Epoch previousEpoch = beaconStateAccessor.GetPreviousEpoch(state);
                epochBoundaryRoot = beaconStateAccessor.GetBlockRoot(state, previousEpoch);
            }
            else if (slot == currentEpochStartSlot)
            {
                epochBoundaryRoot = blockRoot;
            }
            else
            {
                epochBoundaryRoot = beaconStateAccessor.GetBlockRoot(state, currentEpoch);
            }

            Epoch sourceEpoch;
            Root  sourceRoot;

            if (slot < currentEpochStartSlot)
            {
                sourceEpoch = state.PreviousJustifiedCheckpoint.Epoch;
                sourceRoot  = state.PreviousJustifiedCheckpoint.Root;
            }
            else
            {
                sourceEpoch = state.CurrentJustifiedCheckpoint.Epoch;
                sourceRoot  = state.CurrentJustifiedCheckpoint.Root;
            }

            //Crosslink parentCrosslink;
            //if (epochOfSlot == currentEpoch)
            //{
            //    parentCrosslink = state.CurrentCrosslinks[(int)(ulong)shard];
            //}
            //else
            //{
            //    throw new NotImplementedException();
            //}

            Epoch           slotEpoch       = beaconChainUtility.ComputeEpochAtSlot(slot);
            AttestationData attestationData = new AttestationData(
                slot,
                index,
                blockRoot,
                new Checkpoint(sourceEpoch, sourceRoot),
                new Checkpoint(slotEpoch, epochBoundaryRoot));

            return(attestationData);
        }
        public async Task <Attestation> NewAttestationAsync(BlsPublicKey validatorPublicKey,
                                                            bool proofOfCustodyBit, Slot slot, CommitteeIndex index,
                                                            CancellationToken cancellationToken)
        {
            Root head = await _store.GetHeadAsync().ConfigureAwait(false);

            BeaconBlock headBlock   = (await _store.GetSignedBlockAsync(head).ConfigureAwait(false)).Message;
            BeaconState parentState = await _store.GetBlockStateAsync(head).ConfigureAwait(false);

            // Clone state (will mutate) and process outstanding slots
            BeaconState headState = BeaconState.Clone(parentState);

            _beaconStateTransition.ProcessSlots(headState, slot);

            // Set attestation_data.index = index where index is the index associated with the validator's committee.
            ValidatorIndex?validatorIndex = FindValidatorIndexByPublicKey(headState, validatorPublicKey);

            if (validatorIndex == null)
            {
                throw new Exception($"Can not find validator index for public key {validatorPublicKey}");
            }

            // TODO: May need a more efficient way to try and find the committee and position within the committee.
            // Some of this may already be cached in Validator Assignments (generally stable for an epoch),
            // but not with the index within the committee. Easy enough to extend and use the same cache.

            IReadOnlyList <ValidatorIndex> committee =
                _beaconStateAccessor.GetBeaconCommittee(headState, headState.Slot, index);
            int committeeSize = committee.Count;

            int?committeeMemberIndexOfValidator = null;

            for (int committeeMemberIndex = 0; committeeMemberIndex < committee.Count; committeeMemberIndex++)
            {
                if (committee[committeeMemberIndex] == validatorIndex)
                {
                    committeeMemberIndexOfValidator = committeeMemberIndex;
                    break;
                }
            }

            if (committeeMemberIndexOfValidator == null)
            {
                throw new Exception($"Validator index {validatorIndex} is not a member of committee {index}");
            }

            Root beaconBlockRoot = _cryptographyService.HashTreeRoot(headBlock);

            Checkpoint source = headState.CurrentJustifiedCheckpoint;

            Epoch currentEpoch = _beaconStateAccessor.GetCurrentEpoch(headState);
            Slot  startSlot    = _beaconChainUtility.ComputeStartSlotOfEpoch(currentEpoch);
            Root  epochBoundaryBlockRoot;

            if (startSlot == headState.Slot)
            {
                epochBoundaryBlockRoot = beaconBlockRoot;
            }
            else
            {
                epochBoundaryBlockRoot = _beaconStateAccessor.GetBlockRootAtSlot(headState, startSlot);
            }

            Checkpoint target = new Checkpoint(currentEpoch, epochBoundaryBlockRoot);

            AttestationData attestationData = new AttestationData(slot, index, beaconBlockRoot, source, target);

            var aggregationBits = new BitArray(committeeSize);

            aggregationBits.Set(committeeMemberIndexOfValidator.Value, true);

            var attestation = new Attestation(aggregationBits, attestationData, BlsSignature.Zero);

            return(attestation);
        }