public Slot ComputeSlotsSinceEpochStart(Slot slot) { Epoch epoch = _beaconChainUtility.ComputeEpochAtSlot(slot); Slot startSlot = _beaconChainUtility.ComputeStartSlotOfEpoch(epoch); return(slot - startSlot); }
/// <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)); }
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); }