Ejemplo n.º 1
0
        /// <summary>
        /// Transition to the next slot.
        /// </summary>
        public static void NextSlot(IServiceProvider testServiceProvider, BeaconState state)
        {
            BeaconStateTransition beaconStateTransition = testServiceProvider.GetService <BeaconStateTransition>();

            Slot slot = state.Slot + new Slot(1);

            beaconStateTransition.ProcessSlots(state, slot);
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Transition to the start slot of the next epoch
        /// </summary>
        public static void NextEpoch(IServiceProvider testServiceProvider, BeaconState state)
        {
            TimeParameters        timeParameters        = testServiceProvider.GetService <IOptions <TimeParameters> >().Value;
            BeaconStateTransition beaconStateTransition = testServiceProvider.GetService <BeaconStateTransition>();

            Slot slot = (Slot)(state.Slot + timeParameters.SlotsPerEpoch - state.Slot % timeParameters.SlotsPerEpoch);

            beaconStateTransition.ProcessSlots(state, slot);
        }
Ejemplo n.º 3
0
        public static void SignBlock(IServiceProvider testServiceProvider, BeaconState state, BeaconBlock block, ValidatorIndex proposerIndex)
        {
            MiscellaneousParameters miscellaneousParameters = testServiceProvider.GetService <IOptions <MiscellaneousParameters> >().Value;
            TimeParameters          timeParameters          = testServiceProvider.GetService <IOptions <TimeParameters> >().Value;
            MaxOperationsPerBlock   maxOperationsPerBlock   = testServiceProvider.GetService <IOptions <MaxOperationsPerBlock> >().Value;
            SignatureDomains        signatureDomains        = testServiceProvider.GetService <IOptions <SignatureDomains> >().Value;

            ICryptographyService  cryptographyService   = testServiceProvider.GetService <ICryptographyService>();
            BeaconChainUtility    beaconChainUtility    = testServiceProvider.GetService <BeaconChainUtility>();
            BeaconStateAccessor   beaconStateAccessor   = testServiceProvider.GetService <BeaconStateAccessor>();
            BeaconStateTransition beaconStateTransition = testServiceProvider.GetService <BeaconStateTransition>();

            if (state.Slot > block.Slot)
            {
                throw new ArgumentOutOfRangeException("block.Slot", block.Slot, $"Slot of block must be equal or less that state slot {state.Slot}");
            }

            Epoch blockEpoch = beaconChainUtility.ComputeEpochAtSlot(block.Slot);

            if (proposerIndex == ValidatorIndex.None)
            {
                if (block.Slot == state.Slot)
                {
                    proposerIndex = beaconStateAccessor.GetBeaconProposerIndex(state);
                }
                else
                {
                    Epoch stateEpoch = beaconChainUtility.ComputeEpochAtSlot(state.Slot);
                    if (stateEpoch + 1 > blockEpoch)
                    {
                        Console.WriteLine("WARNING: Block slot far away, and no proposer index manually given."
                                          + " Signing block is slow due to transition for proposer index calculation.");
                    }
                    // use stub state to get proposer index of future slot
                    BeaconState stubState = BeaconState.Clone(state);
                    beaconStateTransition.ProcessSlots(stubState, block.Slot);
                    proposerIndex = beaconStateAccessor.GetBeaconProposerIndex(stubState);
                }
            }

            byte[][] privateKeys = TestKeys.PrivateKeys(timeParameters).ToArray();
            byte[]   privateKey  = privateKeys[(int)(ulong)proposerIndex];

            Domain       randaoDomain     = beaconStateAccessor.GetDomain(state, signatureDomains.Randao, blockEpoch);
            Hash32       randaoRevealHash = blockEpoch.HashTreeRoot();
            BlsSignature randaoReveal     = TestSecurity.BlsSign(randaoRevealHash, privateKey, randaoDomain);

            block.Body.SetRandaoReveal(randaoReveal);

            Domain       signatureDomain = beaconStateAccessor.GetDomain(state, signatureDomains.BeaconProposer, blockEpoch);
            Hash32       signingRoot     = cryptographyService.SigningRoot(block);
            BlsSignature signature       = TestSecurity.BlsSign(signingRoot, privateKey, signatureDomain);

            block.SetSignature(signature);
        }
Ejemplo n.º 4
0
        public static SignedBeaconBlock SignBlock(IServiceProvider testServiceProvider, BeaconState state, BeaconBlock block, ValidatorIndex?optionalProposerIndex)
        {
            TimeParameters   timeParameters   = testServiceProvider.GetService <IOptions <TimeParameters> >().Value;
            SignatureDomains signatureDomains = testServiceProvider.GetService <IOptions <SignatureDomains> >().Value;

            ICryptographyService  cryptographyService   = testServiceProvider.GetService <ICryptographyService>();
            BeaconChainUtility    beaconChainUtility    = testServiceProvider.GetService <BeaconChainUtility>();
            BeaconStateAccessor   beaconStateAccessor   = testServiceProvider.GetService <BeaconStateAccessor>();
            BeaconStateTransition beaconStateTransition = testServiceProvider.GetService <BeaconStateTransition>();

            if (state.Slot > block.Slot)
            {
                throw new ArgumentOutOfRangeException("block.Slot", block.Slot, $"Slot of block must be equal or less that state slot {state.Slot}");
            }

            Epoch          blockEpoch = beaconChainUtility.ComputeEpochAtSlot(block.Slot);
            ValidatorIndex proposerIndex;

            if (optionalProposerIndex.HasValue)
            {
                proposerIndex = optionalProposerIndex.Value;
            }
            else
            {
                if (block.Slot == state.Slot)
                {
                    proposerIndex = beaconStateAccessor.GetBeaconProposerIndex(state);
                }
                else
                {
                    Epoch stateEpoch = beaconChainUtility.ComputeEpochAtSlot(state.Slot);
                    if (stateEpoch + 1 > blockEpoch)
                    {
                        Console.WriteLine("WARNING: Block slot far away, and no proposer index manually given."
                                          + " Signing block is slow due to transition for proposer index calculation.");
                    }
                    // use stub state to get proposer index of future slot
                    BeaconState stubState = BeaconState.Clone(state);
                    beaconStateTransition.ProcessSlots(stubState, block.Slot);
                    proposerIndex = beaconStateAccessor.GetBeaconProposerIndex(stubState);
                }
            }

            byte[][] privateKeys = TestKeys.PrivateKeys(timeParameters).ToArray();
            byte[]   privateKey  = privateKeys[(int)(ulong)proposerIndex];

            Root         blockHashTreeRoot = cryptographyService.HashTreeRoot(block);
            Domain       proposerDomain    = beaconStateAccessor.GetDomain(state, signatureDomains.BeaconProposer, blockEpoch);
            Root         signingRoot       = beaconChainUtility.ComputeSigningRoot(blockHashTreeRoot, proposerDomain);
            BlsSignature signature         = TestSecurity.BlsSign(signingRoot, privateKey);

            return(new SignedBeaconBlock(block, signature));
        }
Ejemplo n.º 5
0
        /// <summary>
        /// Processes to the next epoch transition, up to, but not including, the sub-transition named ``process_name``
        /// </summary>
        public static void RunEpochProcessingTo(IServiceProvider testServiceProvider, BeaconState state, TestProcessStep step)
        {
            TimeParameters        timeParameters        = testServiceProvider.GetService <IOptions <TimeParameters> >().Value;
            BeaconStateTransition beaconStateTransition = testServiceProvider.GetService <BeaconStateTransition>();

            Slot slot = (Slot)(state.Slot + (timeParameters.SlotsPerEpoch - state.Slot % timeParameters.SlotsPerEpoch) - 1UL);

            // transition state to slot before epoch state transition
            beaconStateTransition.ProcessSlots(state, slot);

            // start transitioning, do one slot update before the epoch itself.
            beaconStateTransition.ProcessSlot(state);

            // process components of epoch transition before final-updates
            if (step == TestProcessStep.ProcessJustificationAndFinalization)
            {
                return;
            }
            // Note: only run when present. Later phases introduce more to the epoch-processing.
            beaconStateTransition.ProcessJustificationAndFinalization(state);

            if (step == TestProcessStep.ProcessRewardsAndPenalties)
            {
                return;
            }

            beaconStateTransition.ProcessRewardsAndPenalties(state);

            if (step == TestProcessStep.ProcessRegistryUpdates)
            {
                return;
            }

            beaconStateTransition.ProcessRegistryUpdates(state);

            if (step == TestProcessStep.ProcessSlashings)
            {
                return;
            }

            beaconStateTransition.ProcessSlashings(state);

            if (step == TestProcessStep.ProcessFinalUpdates)
            {
                return;
            }

            beaconStateTransition.ProcessFinalUpdates(state);
        }
Ejemplo n.º 6
0
        public static void AddAttestationsToState(IServiceProvider testServiceProvider, BeaconState state, IEnumerable <Attestation> attestations, Slot slot)
        {
            BeaconStateTransition beaconStateTransition = testServiceProvider.GetService <BeaconStateTransition>();

            BeaconBlock block = TestBlock.BuildEmptyBlock(testServiceProvider, state, slot, BlsSignature.Zero);

            foreach (Attestation attestation in attestations)
            {
                block.Body.AddAttestations(attestation);
            }
            beaconStateTransition.ProcessSlots(state, block.Slot);

            SignedBeaconBlock signedBlock = TestBlock.SignBlock(testServiceProvider, state, block, ValidatorIndex.None);

            beaconStateTransition.StateTransition(state, signedBlock, validateResult: false);
        }
Ejemplo n.º 7
0
        public async Task <IList <ValidatorDuty> > GetValidatorDutiesAsync(
            IList <BlsPublicKey> validatorPublicKeys,
            Epoch?optionalEpoch)
        {
            Root head = await _forkChoice.GetHeadAsync(_store).ConfigureAwait(false);

            BeaconState headState = await _store.GetBlockStateAsync(head).ConfigureAwait(false);

            Epoch currentEpoch = _beaconStateAccessor.GetCurrentEpoch(headState);
            Epoch epoch        = optionalEpoch ?? currentEpoch;

            Epoch nextEpoch = currentEpoch + Epoch.One;

            if (epoch > nextEpoch)
            {
                throw new ArgumentOutOfRangeException(nameof(epoch), epoch,
                                                      $"Duties cannot look ahead more than the next epoch {nextEpoch}.");
            }

            Slot startSlot      = _beaconChainUtility.ComputeStartSlotOfEpoch(epoch);
            Root epochStartRoot = await _store.GetAncestorAsync(head, startSlot);

            TimeParameters timeParameters = _timeParameterOptions.CurrentValue;

            (Root epochStartRoot, Epoch epoch)cacheKey = (epochStartRoot, epoch);
            ConcurrentDictionary <BlsPublicKey, ValidatorDuty> dutiesForEpoch =
                await _validatorAssignmentsCache.Cache.GetOrCreateAsync(cacheKey, entry =>
            {
                entry.SlidingExpiration = TimeSpan.FromSeconds(2 * timeParameters.SecondsPerSlot);
                return(Task.FromResult(new ConcurrentDictionary <BlsPublicKey, ValidatorDuty>()));
            }).ConfigureAwait(false);

            IEnumerable <BlsPublicKey> missingValidators = validatorPublicKeys.Except(dutiesForEpoch.Keys);

            if (missingValidators.Any())
            {
                if (_logger.IsDebug())
                {
                    LogDebug.GettingMissingValidatorDutiesForCache(_logger, missingValidators.Count(), epoch,
                                                                   epochStartRoot,
                                                                   null);
                }

                BeaconState storedState = await _store.GetBlockStateAsync(epochStartRoot);

                // Clone, so that it can be safely mutated (transitioned forward)
                BeaconState state = BeaconState.Clone(storedState);

                // Transition to start slot, of target epoch (may have been a skip slot, i.e. stored state root may have been older)
                _beaconStateTransition.ProcessSlots(state, startSlot);

                // Check validators are valid (if not duties are empty).
                IList <DutyDetails> dutyDetailsList = new List <DutyDetails>();
                foreach (BlsPublicKey validatorPublicKey in missingValidators)
                {
                    ValidatorIndex?validatorIndex = FindValidatorIndexByPublicKey(state, validatorPublicKey);

                    if (validatorIndex.HasValue)
                    {
                        bool validatorActive = CheckIfValidatorActive(state, validatorIndex.Value);
                        if (validatorActive)
                        {
                            dutyDetailsList.Add(new DutyDetails(validatorPublicKey, validatorIndex.Value));
                        }
                        else
                        {
                            if (_logger.IsWarn())
                            {
                                Log.ValidatorNotActiveAtEpoch(_logger, epoch, validatorIndex.Value, validatorPublicKey,
                                                              null);
                            }
                            dutiesForEpoch[validatorPublicKey] =
                                new ValidatorDuty(validatorPublicKey, Slot.None, CommitteeIndex.None, Slot.None);
                        }
                    }
                    else
                    {
                        if (_logger.IsWarn())
                        {
                            Log.ValidatorNotFoundAtEpoch(_logger, epoch, validatorPublicKey, null);
                        }
                        dutiesForEpoch[validatorPublicKey] =
                            new ValidatorDuty(validatorPublicKey, Slot.None, CommitteeIndex.None, Slot.None);
                    }
                }

                if (dutyDetailsList.Any())
                {
                    // Check starting state
                    UpdateDutyDetailsForState(dutyDetailsList, state);

                    // Check other slots in epoch, if needed
                    Slot endSlotExclusive = startSlot + new Slot(timeParameters.SlotsPerEpoch);
                    Slot slotToCheck      = startSlot + Slot.One;
                    while (slotToCheck < endSlotExclusive)
                    {
                        _beaconStateTransition.ProcessSlots(state, slotToCheck);
                        UpdateDutyDetailsForState(dutyDetailsList, state);
                        slotToCheck += Slot.One;
                    }

                    // Active validators should always have attestation slots; warn if they don't
                    foreach (var dutyDetails in dutyDetailsList)
                    {
                        if (!dutyDetails.AttestationSlot.HasValue)
                        {
                            if (_logger.IsWarn())
                            {
                                Log.ValidatorDoesNotHaveAttestationSlot(_logger, epoch, dutyDetails.ValidatorPublicKey,
                                                                        null);
                            }
                        }
                    }

                    // Add to cached dictionary
                    foreach (var dutyDetails in dutyDetailsList)
                    {
                        ValidatorDuty validatorDuty =
                            new ValidatorDuty(dutyDetails.ValidatorPublicKey,
                                              dutyDetails.AttestationSlot,
                                              dutyDetails.AttestationCommitteeIndex,
                                              dutyDetails.BlockProposalSlot);
                        dutiesForEpoch[dutyDetails.ValidatorPublicKey] = validatorDuty;
                    }
                }
            }

            return(dutiesForEpoch
                   .Where(x => validatorPublicKeys.Contains(x.Key))
                   .Select(x => x.Value)
                   .ToList());
        }
Ejemplo n.º 8
0
        /// <summary>
        /// Run ``on_attestation`` upon receiving a new ``attestation`` from either within a block or directly on the wire.
        /// An ``attestation`` that is asserted as invalid may be valid at a later time,
        /// consider scheduling it for later processing in such case.
        /// </summary>
        public async Task OnAttestationAsync(IStore store, Attestation attestation)
        {
            if (_logger.IsInfo())
            {
                Log.OnAttestation(_logger, attestation, null);
            }

            TimeParameters timeParameters = _timeParameterOptions.CurrentValue;

            Checkpoint target = attestation.Data.Target;

            // Attestations must be from the current or previous epoch
            Slot  currentSlot  = GetCurrentSlot(store);
            Epoch currentEpoch = _beaconChainUtility.ComputeEpochAtSlot(currentSlot);

            // Use GENESIS_EPOCH for previous when genesis to avoid underflow
            Epoch previousEpoch = currentEpoch > _chainConstants.GenesisEpoch
                ? currentEpoch - new Epoch(1)
                : _chainConstants.GenesisEpoch;

            if (target.Epoch != currentEpoch && target.Epoch != previousEpoch)
            {
                throw new ArgumentOutOfRangeException("attestation.Target.Epoch", target.Epoch,
                                                      $"Attestation target epoch must be either the current epoch {currentEpoch} or previous epoch {previousEpoch}.");
            }

            Epoch dataSlotEpoch = _beaconChainUtility.ComputeEpochAtSlot(attestation.Data.Slot);

            if (attestation.Data.Target.Epoch != dataSlotEpoch)
            {
                throw new ArgumentOutOfRangeException("attestation.Data.Target.Epoch", attestation.Data.Target.Epoch,
                                                      $"Attestation data target epoch must match the attestation data slot {attestation.Data.Slot} (epoch {dataSlotEpoch}).");
            }

            // Attestations target be for a known block. If target block is unknown, delay consideration until the block is found
            BeaconBlock targetBlock = (await store.GetSignedBlockAsync(target.Root).ConfigureAwait(false)).Message;

            // Attestations cannot be from future epochs. If they are, delay consideration until the epoch arrives
            BeaconState targetStoredState = await store.GetBlockStateAsync(target.Root).ConfigureAwait(false);

            BeaconState baseState            = BeaconState.Clone(targetStoredState);
            Slot        targetEpochStartSlot = _beaconChainUtility.ComputeStartSlotOfEpoch(target.Epoch);

            if (currentSlot < targetEpochStartSlot)
            {
                throw new Exception(
                          $"Ättestation target epoch start slot {targetEpochStartSlot} should not be larger than the store current slot {currentSlot}).");
            }

            // Attestations must be for a known block. If block is unknown, delay consideration until the block is found
            BeaconBlock attestationBlock =
                (await store.GetSignedBlockAsync(attestation.Data.BeaconBlockRoot).ConfigureAwait(false)).Message;

            // Attestations must not be for blocks in the future. If not, the attestation should not be considered
            if (attestationBlock.Slot > attestation.Data.Slot)
            {
                throw new Exception(
                          $"Attestation data root slot {attestationBlock.Slot} should not be larger than the attestation data slot {attestation.Data.Slot}).");
            }

            // Store target checkpoint state if not yet seen
            BeaconState?targetState = await store.GetCheckpointStateAsync(target, false).ConfigureAwait(false);

            if (targetState == null)
            {
                _beaconStateTransition.ProcessSlots(baseState, targetEpochStartSlot);
                await store.SetCheckpointStateAsync(target, baseState).ConfigureAwait(false);

                targetState = baseState;
            }

            // Attestations can only affect the fork choice of subsequent slots.
            // Delay consideration in the fork choice until their slot is in the past.
            Slot newCurrentSlot = GetCurrentSlot(store);

            if (newCurrentSlot < attestation.Data.Slot + 1)
            {
                throw new Exception(
                          $"Attestation data slot {attestation.Data.Slot} should not be larger than the store current slot {newCurrentSlot}).");
            }

            // Get state at the `target` to validate attestation and calculate the committees
            IndexedAttestation indexedAttestation =
                _beaconStateAccessor.GetIndexedAttestation(targetState, attestation);
            Domain domain = _beaconStateAccessor.GetDomain(targetState,
                                                           _signatureDomainOptions.CurrentValue.BeaconAttester, indexedAttestation.Data.Target.Epoch);
            bool isValid = _beaconChainUtility.IsValidIndexedAttestation(targetState, indexedAttestation, domain);

            if (!isValid)
            {
                throw new Exception($"Indexed attestation {indexedAttestation} is not valid.");
            }

            // Update latest messages
            IEnumerable <ValidatorIndex> attestingIndices =
                _beaconStateAccessor.GetAttestingIndices(targetState, attestation.Data, attestation.AggregationBits);

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

                if (latestMessage == null || target.Epoch > latestMessage !.Epoch)
                {
                    latestMessage = new LatestMessage(target.Epoch, attestation.Data.BeaconBlockRoot);
                    await store.SetLatestMessageAsync(index, latestMessage).ConfigureAwait(false);
                }
            }
        }
Ejemplo n.º 9
0
        public static BeaconBlock BuildEmptyBlock(IServiceProvider testServiceProvider, BeaconState state, Slot slot, BlsSignature randaoReveal)
        {
            //if (slot) is none

            TimeParameters   timeParameters   = testServiceProvider.GetService <IOptions <TimeParameters> >().Value;
            SignatureDomains signatureDomains = testServiceProvider.GetService <IOptions <SignatureDomains> >().Value;

            ICryptographyService  cryptographyService   = testServiceProvider.GetService <ICryptographyService>();
            BeaconChainUtility    beaconChainUtility    = testServiceProvider.GetService <BeaconChainUtility>();
            BeaconStateAccessor   beaconStateAccessor   = testServiceProvider.GetService <BeaconStateAccessor>();
            BeaconStateTransition beaconStateTransition = testServiceProvider.GetService <BeaconStateTransition>();

            Eth1Data eth1Data = new Eth1Data(Root.Zero, state.Eth1DepositIndex, Bytes32.Zero);

            Root stateRoot = !state.LatestBlockHeader.StateRoot.Equals(Root.Zero)
                ? state.LatestBlockHeader.StateRoot
                : cryptographyService.HashTreeRoot(state);
            BeaconBlockHeader previousBlockHeader = new BeaconBlockHeader(state.LatestBlockHeader.Slot,
                                                                          state.LatestBlockHeader.ParentRoot, stateRoot, state.LatestBlockHeader.BodyRoot);
            Root previousBlockHashTreeRoot = cryptographyService.HashTreeRoot(previousBlockHeader);

            if (randaoReveal.Equals(BlsSignature.Zero))
            {
                Epoch          blockEpoch = beaconChainUtility.ComputeEpochAtSlot(slot);
                ValidatorIndex proposerIndex;
                if (slot == state.Slot)
                {
                    proposerIndex = beaconStateAccessor.GetBeaconProposerIndex(state);
                }
                else
                {
                    Epoch stateEpoch = beaconChainUtility.ComputeEpochAtSlot(state.Slot);
                    if (blockEpoch > stateEpoch + 1)
                    {
                        Console.WriteLine("WARNING: Block slot (epoch {0}) far away from state (epoch {1}), and no proposer index manually given."
                                          + " Signing block is slow due to transition for proposer index calculation.", blockEpoch, stateEpoch);
                    }

                    // use stub state to get proposer index of future slot
                    BeaconState stubState = BeaconState.Clone(state);
                    beaconStateTransition.ProcessSlots(stubState, slot);
                    proposerIndex = beaconStateAccessor.GetBeaconProposerIndex(stubState);
                }

                byte[][] privateKeys = TestKeys.PrivateKeys(timeParameters).ToArray();
                byte[]   privateKey  = privateKeys[(int)(ulong)proposerIndex];

                Domain randaoDomain      = beaconStateAccessor.GetDomain(state, signatureDomains.Randao, blockEpoch);
                Root   epochHashTreeRoot = cryptographyService.HashTreeRoot(blockEpoch);
                Root   randaoSigningRoot = beaconChainUtility.ComputeSigningRoot(epochHashTreeRoot, randaoDomain);
                randaoReveal = TestSecurity.BlsSign(randaoSigningRoot, privateKey);
            }

            BeaconBlock emptyBlock = new BeaconBlock(slot,
                                                     previousBlockHashTreeRoot,
                                                     Root.Zero,
                                                     new BeaconBlockBody(
                                                         randaoReveal,
                                                         eth1Data,
                                                         new Bytes32(),
                                                         Array.Empty <ProposerSlashing>(),
                                                         Array.Empty <AttesterSlashing>(),
                                                         Array.Empty <Attestation>(),
                                                         Array.Empty <Deposit>(),
                                                         Array.Empty <SignedVoluntaryExit>()
                                                         ));

            return(emptyBlock);
        }
Ejemplo n.º 10
0
        public async Task <ValidatorDuty> GetValidatorDutyAsync(BlsPublicKey validatorPublicKey, Epoch epoch)
        {
            Root head = await _forkChoice.GetHeadAsync(_store).ConfigureAwait(false);

            BeaconState headState = await _store.GetBlockStateAsync(head).ConfigureAwait(false);

            Epoch currentEpoch = _beaconStateAccessor.GetCurrentEpoch(headState);
            Epoch nextEpoch    = currentEpoch + Epoch.One;

            if (epoch == Epoch.None)
            {
                epoch = currentEpoch;
            }
            else if (epoch > nextEpoch)
            {
                throw new ArgumentOutOfRangeException(nameof(epoch), epoch,
                                                      $"Duties cannot look ahead more than the next epoch {nextEpoch}.");
            }

            TimeParameters timeParameters = _timeParameterOptions.CurrentValue;

            Slot startSlot = _beaconChainUtility.ComputeStartSlotOfEpoch(epoch);
            Slot endSlot   = startSlot + new Slot(timeParameters.SlotsPerEpoch);

            Duty duty = new Duty()
            {
                AttestationSlot           = Slot.None,
                AttestationCommitteeIndex = CommitteeIndex.None,
                BlockProposalSlot         = Slot.None
            };

            if (epoch == nextEpoch)
            {
                // Clone for next or current, so that it can be safely mutated (transitioned forward)
                BeaconState state = BeaconState.Clone(headState);
                _beaconStateTransition.ProcessSlots(state, startSlot);

                // Check base state
                ValidatorIndex validatorIndex = CheckValidatorIndex(state, validatorPublicKey);
                duty = CheckStateDuty(state, validatorIndex, duty);

                // Check future states
                duty = CheckFutureSlots(state, endSlot, validatorIndex, duty);
            }
            else if (epoch == currentEpoch)
            {
                // Take block slot and roots before cloning (for historical checks)
                IReadOnlyList <Root> historicalBlockRoots = headState.BlockRoots;
                Slot        fromSlot = headState.Slot;
                BeaconState state    = BeaconState.Clone(headState);

                // Check base state
                ValidatorIndex validatorIndex = CheckValidatorIndex(state, validatorPublicKey);
                duty = CheckStateDuty(state, validatorIndex, duty);

                // Check future states
                duty = CheckFutureSlots(state, endSlot, validatorIndex, duty);

                // Check historical states
                if (startSlot < fromSlot && (duty.AttestationSlot == Slot.None || duty.BlockProposalSlot == Slot.None))
                {
                    duty = await CheckHistoricalSlotsAsync(_store, historicalBlockRoots, fromSlot, startSlot,
                                                           validatorIndex, duty).ConfigureAwait(false);
                }
            }
            else
            {
                Root endRoot = await _forkChoice.GetAncestorAsync(_store, head, endSlot - Slot.One);

                BeaconState state = await _store.GetBlockStateAsync(endRoot).ConfigureAwait(false);

                // Check base state
                ValidatorIndex validatorIndex = CheckValidatorIndex(state, validatorPublicKey);
                duty = CheckStateDuty(state, validatorIndex, duty);

                // Check historical states
                IReadOnlyList <Root> historicalBlockRoots = state.BlockRoots;
                if (duty.AttestationSlot == Slot.None || duty.BlockProposalSlot == Slot.None)
                {
                    Slot fromSlot = state.Slot;
                    duty = await CheckHistoricalSlotsAsync(_store, historicalBlockRoots, fromSlot, startSlot,
                                                           validatorIndex, duty).ConfigureAwait(false);
                }
            }

            // HACK: Shards were removed from Phase 0, but analogy is committee index, so use for initial testing.
            Shard attestationShard = new Shard((ulong)duty.AttestationCommitteeIndex);

            ValidatorDuty validatorDuty =
                new ValidatorDuty(validatorPublicKey, duty.AttestationSlot, attestationShard, duty.BlockProposalSlot);

            return(validatorDuty);
        }
Ejemplo n.º 11
0
 private void PrepareStateForHeaderProcessing(BeaconState state,
                                              BeaconStateTransition beaconStateTransition)
 {
     beaconStateTransition.ProcessSlots(state, state.Slot + new Slot(1));
 }
Ejemplo n.º 12
0
        public async Task <ValidatorDuty> GetValidatorDutyAsync(BlsPublicKey validatorPublicKey, Epoch epoch)
        {
            if (!_storeProvider.TryGetStore(out IStore? retrievedStore))
            {
                throw new Exception("Beacon chain is currently syncing or waiting for genesis.");
            }

            IStore store = retrievedStore !;
            Hash32 head  = await _forkChoice.GetHeadAsync(store);

            if (!store.TryGetBlockState(head, out BeaconState? headState))
            {
                throw new Exception($"Head state {head} not found.");
            }

            Epoch currentEpoch = _beaconStateAccessor.GetCurrentEpoch(headState !);
            Epoch nextEpoch    = currentEpoch + Epoch.One;

            if (epoch == Epoch.None)
            {
                epoch = currentEpoch;
            }
            else if (epoch > nextEpoch)
            {
                throw new ArgumentOutOfRangeException(nameof(epoch), epoch,
                                                      $"Duties cannot look ahead more than the next epoch {nextEpoch}.");
            }

            TimeParameters timeParameters = _timeParameterOptions.CurrentValue;

            Slot startSlot = _beaconChainUtility.ComputeStartSlotOfEpoch(epoch);
            Slot endSlot   = startSlot + new Slot(timeParameters.SlotsPerEpoch);

            Slot           attestationSlot           = Slot.None;
            CommitteeIndex attestationCommitteeIndex = CommitteeIndex.None;
            Slot           blockProposalSlot         = Slot.None;

            if (epoch == nextEpoch)
            {
                // Clone for next or current, so that it can be safely mutated (transitioned forward)
                BeaconState state = BeaconState.Clone(headState !);
                _beaconStateTransition.ProcessSlots(state, startSlot);

                // Check base state
                ValidatorIndex validatorIndex = CheckValidatorIndex(state, validatorPublicKey);
                CheckStateDuty(state, validatorIndex, ref attestationSlot, ref attestationCommitteeIndex, ref blockProposalSlot);

                // Check future states
                CheckFutureSlots(state, endSlot, validatorIndex, ref attestationSlot, ref attestationCommitteeIndex, ref blockProposalSlot);
            }
            else if (epoch == currentEpoch)
            {
                // Take block slot and roots before cloning (for historical checks)
                IReadOnlyList <Hash32> historicalBlockRoots = headState !.BlockRoots;
                Slot        fromSlot = headState !.Slot;
                BeaconState state    = BeaconState.Clone(headState !);

                // Check base state
                ValidatorIndex validatorIndex = CheckValidatorIndex(state, validatorPublicKey);
                CheckStateDuty(state, validatorIndex, ref attestationSlot, ref attestationCommitteeIndex, ref blockProposalSlot);

                // Check future states
                CheckFutureSlots(state, endSlot, validatorIndex, ref attestationSlot, ref attestationCommitteeIndex,
                                 ref blockProposalSlot);

                // Check historical states
                if (startSlot < fromSlot && (attestationSlot == Slot.None || blockProposalSlot == Slot.None))
                {
                    CheckHistoricalSlots(store, historicalBlockRoots, fromSlot, startSlot, validatorIndex,
                                         ref attestationSlot, ref attestationCommitteeIndex, ref blockProposalSlot);
                }
            }
            else
            {
                Hash32 endRoot = _forkChoice.GetAncestor(store, head, endSlot - Slot.One);
                if (!store.TryGetBlockState(endRoot, out BeaconState? endState))
                {
                    throw new Exception($"State {endRoot} for slot {endSlot} not found.");
                }
                BeaconState state = endState !;

                // Check base state
                ValidatorIndex validatorIndex = CheckValidatorIndex(state, validatorPublicKey);
                CheckStateDuty(state, validatorIndex, ref attestationSlot, ref attestationCommitteeIndex, ref blockProposalSlot);

                // Check historical states
                IReadOnlyList <Hash32> historicalBlockRoots = state.BlockRoots;
                Slot fromSlot = state.Slot;
                if (attestationSlot == Slot.None || blockProposalSlot == Slot.None)
                {
                    CheckHistoricalSlots(store, historicalBlockRoots, fromSlot, startSlot, validatorIndex,
                                         ref attestationSlot, ref attestationCommitteeIndex, ref blockProposalSlot);
                }
            }

            // HACK: Shards were removed from Phase 0, but analogy is committee index, so use for initial testing.
            Shard         attestationShard = new Shard((ulong)attestationCommitteeIndex);
            ValidatorDuty validatorDuty    =
                new ValidatorDuty(validatorPublicKey, attestationSlot, attestationShard, blockProposalSlot);

            return(validatorDuty);
        }
Ejemplo n.º 13
0
        /// <summary>
        /// Run ``on_attestation`` upon receiving a new ``attestation`` from either within a block or directly on the wire.
        /// An ``attestation`` that is asserted as invalid may be valid at a later time,
        /// consider scheduling it for later processing in such case.
        /// </summary>
        public void OnAttestation(IStore store, Attestation attestation)
        {
            var initialValues  = _initialValueOptions.CurrentValue;
            var timeParameters = _timeParameterOptions.CurrentValue;

            var target = attestation.Data.Target;

            // Attestations must be from the current or previous epoch
            var currentSlot  = GetCurrentSlot(store);
            var currentEpoch = _beaconChainUtility.ComputeEpochAtSlot(currentSlot);

            // Use GENESIS_EPOCH for previous when genesis to avoid underflow
            var previousEpoch = currentEpoch > initialValues.GenesisEpoch
                ? currentEpoch - new Epoch(1)
                : initialValues.GenesisEpoch;

            if (target.Epoch != currentEpoch && target.Epoch != previousEpoch)
            {
                throw new ArgumentOutOfRangeException("attestation.Target.Epoch", target.Epoch, $"Attestation target epoch must be either the current epoch {currentEpoch} or previous epoch {previousEpoch}.");
            }
            // Cannot calculate the current shuffling if have not seen the target
            if (!store.TryGetBlock(target.Root, out var targetBlock))
            {
                throw new ArgumentOutOfRangeException("attestation.Target.Root", target.Root, "Attestation target root not found in the block history.");
            }

            // Attestations target be for a known block. If target block is unknown, delay consideration until the block is found
            if (!store.TryGetBlockState(target.Root, out var targetStoredState))
            {
                throw new ArgumentOutOfRangeException("attestation.Target.Root", target.Root, "Attestation target root not found in the block stores history.");
            }

            // Attestations cannot be from future epochs. If they are, delay consideration until the epoch arrives
            var baseState                = BeaconState.Clone(targetStoredState !);
            var targetEpochStartSlot     = _beaconChainUtility.ComputeStartSlotOfEpoch(target.Epoch);
            var targetEpochStartSlotTime = baseState.GenesisTime + (ulong)targetEpochStartSlot * timeParameters.SecondsPerSlot;

            if (store.Time < targetEpochStartSlotTime)
            {
                throw new Exception($"Ättestation target state time {targetEpochStartSlotTime} should not be larger than the store time {store.Time}).");
            }

            // Attestations must be for a known block. If block is unknown, delay consideration until the block is found
            if (!store.TryGetBlock(attestation.Data.BeaconBlockRoot, out var storedAttestationBlock))
            {
                throw new ArgumentOutOfRangeException("attestation.Data.BeaconBlockRoot", attestation.Data.BeaconBlockRoot, "Attestation data root not found in the block history.");
            }

            var attestationBlock = storedAttestationBlock !;

            // Attestations must not be for blocks in the future. If not, the attestation should not be considered
            if (attestationBlock.Slot > attestation.Data.Slot)
            {
                throw new Exception($"Attestation data root slot {attestationBlock.Slot} should not be larger than the attestation data slot {attestation.Data.Slot}).");
            }

            // Store target checkpoint state if not yet seen

            if (!store.TryGetCheckpointState(target, out var targetState))
            {
                _beaconStateTransition.ProcessSlots(baseState, targetEpochStartSlot);
                store.SetCheckpointState(target, baseState);
                targetState = baseState;
            }

            // Attestations can only affect the fork choice of subsequent slots.
            // Delay consideration in the fork choice until their slot is in the past.
            //var attestationDataSlotTime = ((ulong)attestation.Data.Slot + 1) * timeParameters.SecondsPerSlot;
            ulong attestationDataSlotTime = targetState !.GenesisTime + ((ulong)attestation.Data.Slot + 1) * timeParameters.SecondsPerSlot;

            if (store.Time < attestationDataSlotTime)
            {
                throw new Exception($"Ättestation data time {attestationDataSlotTime} should not be larger than the store time {store.Time}).");
            }

            // Get state at the `target` to validate attestation and calculate the committees
            var indexedAttestation = _beaconStateAccessor.GetIndexedAttestation(targetState, attestation);
            var domain             = _beaconStateAccessor.GetDomain(targetState, _signatureDomainOptions.CurrentValue.BeaconAttester, indexedAttestation.Data.Target.Epoch);
            var isValid            = _beaconChainUtility.IsValidIndexedAttestation(targetState, indexedAttestation, domain);

            if (!isValid)
            {
                throw new Exception($"Indexed attestation {indexedAttestation} is not valid.");
            }

            // Update latest messages
            var attestingIndices = _beaconStateAccessor.GetAttestingIndices(targetState, attestation.Data, attestation.AggregationBits);

            foreach (var index in attestingIndices)
            {
                if (!store.TryGetLatestMessage(index, out var latestMessage) || target.Epoch > latestMessage !.Epoch)
                {
                    latestMessage = new LatestMessage(target.Epoch, attestation.Data.BeaconBlockRoot);
                    store.SetLatestMessage(index, latestMessage);
                }
            }
        }
Ejemplo n.º 14
0
        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);
        }