示例#1
0
        public void ProposerIndexForFirstTwoEpochsMustBeValid()
        {
            // Arrange
            IServiceCollection testServiceCollection = TestSystem.BuildTestServiceCollection(useStore: true);

            testServiceCollection.AddSingleton <IHostEnvironment>(Substitute.For <IHostEnvironment>());
            ServiceProvider testServiceProvider = testServiceCollection.BuildServiceProvider();
            BeaconState     state      = TestState.PrepareTestState(testServiceProvider);
            ForkChoice      forkChoice = testServiceProvider.GetService <ForkChoice>();
            // Get genesis store initialise MemoryStoreProvider with the state
            IStore store = forkChoice.GetGenesisStore(state);

            // Move forward time
            BeaconStateAccessor beaconStateAccessor = testServiceProvider.GetService <BeaconStateAccessor>();
            TimeParameters      timeParameters      = testServiceProvider.GetService <IOptions <TimeParameters> >().Value;
            ulong          time                  = state.GenesisTime + 1;
            ulong          nextSlotTime          = state.GenesisTime;
            ValidatorIndex maximumValidatorIndex = new ValidatorIndex((ulong)state.Validators.Count - 1);

            ValidatorIndex validatorIndex0 = beaconStateAccessor.GetBeaconProposerIndex(state);

            Console.WriteLine("Slot {0}, time {1} = proposer index {2}", state.Slot, time, validatorIndex0);
            validatorIndex0.ShouldBeLessThanOrEqualTo(maximumValidatorIndex);

            List <ValidatorIndex> proposerIndexes = new List <ValidatorIndex>();

            proposerIndexes.Add(validatorIndex0);

            for (int slotIndex = 1; slotIndex <= 16; slotIndex++)
            {
                // Slot 1
                nextSlotTime = nextSlotTime + timeParameters.SecondsPerSlot;
                while (time < nextSlotTime)
                {
                    forkChoice.OnTick(store, time);
                    time++;
                }

                forkChoice.OnTick(store, time);
                time++;
                BeaconBlock block = TestBlock.BuildEmptyBlockForNextSlot(testServiceProvider, state, signed: true);
                TestState.StateTransitionAndSignBlock(testServiceProvider, state, block);
                forkChoice.OnBlock(store, block);
                forkChoice.OnTick(store, time);
                time++;

                ValidatorIndex validatorIndex = beaconStateAccessor.GetBeaconProposerIndex(state);
                Console.WriteLine("Slot {0}, time {1} = proposer index {2}", state.Slot, time, validatorIndex);
                validatorIndex.ShouldBeLessThanOrEqualTo(maximumValidatorIndex);
                proposerIndexes.Add(validatorIndex);
            }

            for (var slotIndex = 0; slotIndex < proposerIndexes.Count; slotIndex++)
            {
                ValidatorIndex proposerIndex = proposerIndexes[slotIndex];
                Validator      proposer      = state.Validators[(int)(ulong)proposerIndex];
                Console.WriteLine("Slot {0} = proposer index {1}, public key {2}", slotIndex, proposerIndex, proposer.PublicKey);
            }
        }
示例#2
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);
        }
示例#3
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));
        }
        //    Run ``process_attester_slashing``, yielding:
        //  - pre-state('pre')
        //  - attester_slashing('attester_slashing')
        //  - post-state('post').
        //If ``valid == False``, run expecting ``AssertionError``
        private void RunAttesterSlashingProcessing(IServiceProvider testServiceProvider, BeaconState state, AttesterSlashing attesterSlashing, bool expectValid)
        {
            ChainConstants      chainConstants      = testServiceProvider.GetService <ChainConstants>();
            StateListLengths    stateListLengths    = testServiceProvider.GetService <IOptions <StateListLengths> >().Value;
            RewardsAndPenalties rewardsAndPenalties = testServiceProvider.GetService <IOptions <RewardsAndPenalties> >().Value;

            BeaconStateAccessor   beaconStateAccessor   = testServiceProvider.GetService <BeaconStateAccessor>();
            BeaconStateTransition beaconStateTransition = testServiceProvider.GetService <BeaconStateTransition>();

            if (!expectValid)
            {
                Should.Throw <Exception>(() =>
                {
                    beaconStateTransition.ProcessAttesterSlashing(state, attesterSlashing);
                });
                return;
            }

            var slashedIndices = attesterSlashing.Attestation1.CustodyBit0Indices
                                 .Union(attesterSlashing.Attestation1.CustodyBit1Indices)
                                 .ToList();

            ValidatorIndex proposerIndex         = beaconStateAccessor.GetBeaconProposerIndex(state);
            Gwei           preProposerBalance    = TestState.GetBalance(state, proposerIndex);
            var            preSlashings          = slashedIndices.ToDictionary(x => x, x => TestState.GetBalance(state, x));
            var            preWithdrawableEpochs = slashedIndices.ToDictionary(x => x, x => state.Validators[(int)(ulong)x].WithdrawableEpoch);

            Gwei totalProposerRewards = preSlashings.Values.Aggregate(Gwei.Zero, (sum, x) => sum + x / rewardsAndPenalties.WhistleblowerRewardQuotient);

            // Process slashing
            beaconStateTransition.ProcessAttesterSlashing(state, attesterSlashing);

            foreach (ValidatorIndex slashedIndex in slashedIndices)
            {
                Console.WriteLine($"Checking index {slashedIndex}");
                Epoch     preWithdrawableEpoch = preWithdrawableEpochs[slashedIndex];
                Validator slashedValidator     = state.Validators[(int)(ulong)slashedIndex];

                // Check Slashing
                slashedValidator.IsSlashed.ShouldBeTrue();
                slashedValidator.ExitEpoch.ShouldBeLessThan(chainConstants.FarFutureEpoch);
                if (preWithdrawableEpoch < chainConstants.FarFutureEpoch)
                {
                    ulong slashingsEpoch            = beaconStateAccessor.GetCurrentEpoch(state) + stateListLengths.EpochsPerSlashingsVector;
                    Epoch expectedWithdrawableEpoch = Epoch.Max(preWithdrawableEpoch, (Epoch)slashingsEpoch);
                    slashedValidator.WithdrawableEpoch.ShouldBe(expectedWithdrawableEpoch);
                }
                else
                {
                    slashedValidator.WithdrawableEpoch.ShouldBeLessThan(chainConstants.FarFutureEpoch);
                }

                Gwei preSlashing    = preSlashings[slashedIndex];
                Gwei slashedBalance = TestState.GetBalance(state, slashedIndex);
                slashedBalance.ShouldBeLessThan(preSlashing);
            }

            if (!slashedIndices.Contains(proposerIndex))
            {
                // gained whistleblower reward
                Gwei expectedProposerBalance = preProposerBalance + totalProposerRewards;
                Gwei proposerBalance         = TestState.GetBalance(state, proposerIndex);
                proposerBalance.ShouldBe(expectedProposerBalance);
            }
            else
            {
                // gained rewards for all slashings, which may include others. And only lost that of themselves.
                Gwei expectedProposerBalance = preProposerBalance + totalProposerRewards
                                               - (preSlashings[proposerIndex] / rewardsAndPenalties.MinimumSlashingPenaltyQuotient);
                Gwei proposerBalance = TestState.GetBalance(state, proposerIndex);
                proposerBalance.ShouldBe(expectedProposerBalance);
            }
        }
示例#5
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);
        }