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); } }
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); }
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); } }
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); }