Exemple #1
0
        public void FullAttestations()
        {
            // Arrange
            IServiceProvider testServiceProvider = TestSystem.BuildTestServiceProvider();
            BeaconState      state = TestState.PrepareTestState(testServiceProvider);

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

            var attestations = PrepareStateWithFullAttestations(testServiceProvider, state);

            BeaconState preState = BeaconState.Clone(state);

            // Act
            RunProcessRewardsAndPenalties(testServiceProvider, state);

            // Assert
            var pendingAttestations = attestations.Select(x => new PendingAttestation(x.AggregationBits, x.Data, Slot.None, ValidatorIndex.None));
            var attestingIndices    = beaconStateTransition.GetUnslashedAttestingIndices(state, pendingAttestations).ToList();

            attestingIndices.Count.ShouldBeGreaterThan(0);

            for (int index = 0; index < preState.Validators.Count; index++)
            {
                ValidatorIndex validatorIndex = new ValidatorIndex((ulong)index);
                if (attestingIndices.Contains(validatorIndex))
                {
                    state.Balances[index].ShouldBeGreaterThan(preState.Balances[index], $"Attesting balance {index}");
                }
                else
                {
                    state.Balances[index].ShouldBeLessThan(preState.Balances[index], $"Non-attesting balance {index}");
                }
            }
        }
Exemple #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);
        }
Exemple #3
0
        public async Task ShorterChainButHeavierWeight()
        {
            // Arrange
            IServiceProvider testServiceProvider = TestSystem.BuildTestServiceProvider(useStore: true);
            BeaconState      state = TestState.PrepareTestState(testServiceProvider);

            // Initialization
            ICryptographyService cryptographyService = testServiceProvider.GetService <ICryptographyService>();
            IForkChoice          forkChoice          = testServiceProvider.GetService <IForkChoice>();
            IStore store = testServiceProvider.GetService <IStore>();
            await forkChoice.InitializeForkChoiceStoreAsync(store, state);

            BeaconState genesisState = BeaconState.Clone(state);

            // build longer tree
            Root        longRoot  = Root.Zero;
            BeaconState longState = BeaconState.Clone(genesisState);

            for (int i = 0; i < 3; i++)
            {
                BeaconBlock       longBlock       = TestBlock.BuildEmptyBlockForNextSlot(testServiceProvider, longState, BlsSignature.Zero);
                SignedBeaconBlock signedLongBlock = TestState.StateTransitionAndSignBlock(testServiceProvider, longState, longBlock);
                await AddBlockToStore(testServiceProvider, store, signedLongBlock);

                if (i == 2)
                {
                    longRoot = cryptographyService.HashTreeRoot(longBlock);
                }
            }

            // build short tree
            BeaconState shortState = BeaconState.Clone(genesisState);
            BeaconBlock shortBlock = TestBlock.BuildEmptyBlockForNextSlot(testServiceProvider, shortState, BlsSignature.Zero);

            shortBlock.Body.SetGraffiti(new Bytes32(Enumerable.Repeat((byte)0x42, 32).ToArray()));
            TestBlock.SignBlock(testServiceProvider, shortState, shortBlock, ValidatorIndex.None);
            SignedBeaconBlock signedShortBlock = TestState.StateTransitionAndSignBlock(testServiceProvider, shortState, shortBlock);

            await AddBlockToStore(testServiceProvider, store, signedShortBlock);

            Attestation shortAttestation = TestAttestation.GetValidAttestation(testServiceProvider, shortState, shortBlock.Slot, CommitteeIndex.None, signed: true);

            await AddAttestationToStore(testServiceProvider, store, shortAttestation);

            // Act
            Root headRoot = await forkChoice.GetHeadAsync(store);

            // Assert
            Root expectedRoot = cryptographyService.HashTreeRoot(shortBlock);

            headRoot.ShouldBe(expectedRoot);
            headRoot.ShouldNotBe(longRoot);
        }
        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));
        }
Exemple #5
0
        public async Task ShorterChainButHeavierWeight()
        {
            // Arrange
            IServiceProvider testServiceProvider = TestSystem.BuildTestServiceProvider(useStore: true);
            BeaconState      state = TestState.PrepareTestState(testServiceProvider);

            MiscellaneousParameters miscellaneousParameters = testServiceProvider.GetService <IOptions <MiscellaneousParameters> >().Value;
            MaxOperationsPerBlock   maxOperationsPerBlock   = testServiceProvider.GetService <IOptions <MaxOperationsPerBlock> >().Value;

            // Initialization
            ICryptographyService cryptographyService = testServiceProvider.GetService <ICryptographyService>();
            ForkChoice           forkChoice          = testServiceProvider.GetService <ForkChoice>();
            IStore      store        = forkChoice.GetGenesisStore(state);
            BeaconState genesisState = BeaconState.Clone(state);

            // build longer tree
            Hash32      longRoot  = default;
            BeaconState longState = BeaconState.Clone(genesisState);

            for (int i = 0; i < 3; i++)
            {
                BeaconBlock longBlock = TestBlock.BuildEmptyBlockForNextSlot(testServiceProvider, longState, signed: true);
                TestState.StateTransitionAndSignBlock(testServiceProvider, longState, longBlock);
                await AddBlockToStore(testServiceProvider, store, longBlock);

                if (i == 2)
                {
                    longRoot = cryptographyService.SigningRoot(longBlock);
                }
            }

            // build short tree
            BeaconState shortState = BeaconState.Clone(genesisState);
            BeaconBlock shortBlock = TestBlock.BuildEmptyBlockForNextSlot(testServiceProvider, shortState, signed: true);

            shortBlock.Body.SetGraffiti(new Bytes32(Enumerable.Repeat((byte)0x42, 32).ToArray()));
            TestBlock.SignBlock(testServiceProvider, shortState, shortBlock, ValidatorIndex.None);
            TestState.StateTransitionAndSignBlock(testServiceProvider, shortState, shortBlock);
            await AddBlockToStore(testServiceProvider, store, shortBlock);

            Attestation shortAttestation = TestAttestation.GetValidAttestation(testServiceProvider, shortState, shortBlock.Slot, CommitteeIndex.None, signed: true);

            await AddAttestationToStore(testServiceProvider, store, shortAttestation);

            // Act
            Hash32 headRoot = await forkChoice.GetHeadAsync(store);

            // Assert
            Hash32 expectedRoot = cryptographyService.SigningRoot(shortBlock);

            headRoot.ShouldBe(expectedRoot);
            headRoot.ShouldNotBe(longRoot);
        }
Exemple #6
0
        public void GenesisEpochFullAttestationsNoRewards()
        {
            // Arrange
            IServiceProvider testServiceProvider = TestSystem.BuildTestServiceProvider();
            BeaconState      state = TestState.PrepareTestState(testServiceProvider);

            InitialValues  initialValues  = testServiceProvider.GetService <IOptions <InitialValues> >().Value;
            TimeParameters timeParameters = testServiceProvider.GetService <IOptions <TimeParameters> >().Value;

            BeaconChainUtility beaconChainUtility = testServiceProvider.GetService <BeaconChainUtility>();

            var attestations = new List <Attestation>();

            for (Slot slot = Slot.Zero; slot < timeParameters.SlotsPerEpoch - new Slot(1); slot += new Slot(1))
            {
                // create an attestation for each slot
                if (slot < timeParameters.SlotsPerEpoch)
                {
                    Attestation attestation = TestAttestation.GetValidAttestation(testServiceProvider, state, slot, CommitteeIndex.None, signed: true);
                    attestations.Add(attestation);
                }

                // fill each created slot in state after inclusion delay
                if (slot >= timeParameters.MinimumAttestationInclusionDelay)
                {
                    Slot        index = slot - timeParameters.MinimumAttestationInclusionDelay;
                    Attestation includeAttestation = attestations[(int)(ulong)index];
                    TestAttestation.AddAttestationsToState(testServiceProvider, state, new[] { includeAttestation }, state.Slot);
                }

                TestState.NextSlot(testServiceProvider, state);
            }

            // ensure has not cross the epoch boundary
            Epoch stateEpoch = beaconChainUtility.ComputeEpochAtSlot(state.Slot);

            stateEpoch.ShouldBe(initialValues.GenesisEpoch);

            BeaconState preState = BeaconState.Clone(state);

            // Act
            RunProcessRewardsAndPenalties(testServiceProvider, state);

            // Assert
            for (int index = 0; index < preState.Validators.Count; index++)
            {
                state.Balances[index].ShouldBe(preState.Balances[index], $"Balance {index}");
            }
        }
Exemple #7
0
        public async Task SplitTieBreakerNoAttestations()
        {
            // Arrange
            IServiceProvider testServiceProvider = TestSystem.BuildTestServiceProvider(useStore: true);
            BeaconState      state = TestState.PrepareTestState(testServiceProvider);

            MiscellaneousParameters miscellaneousParameters = testServiceProvider.GetService <IOptions <MiscellaneousParameters> >().Value;
            MaxOperationsPerBlock   maxOperationsPerBlock   = testServiceProvider.GetService <IOptions <MaxOperationsPerBlock> >().Value;

            // Initialization
            ICryptographyService cryptographyService = testServiceProvider.GetService <ICryptographyService>();
            ForkChoice           forkChoice          = testServiceProvider.GetService <ForkChoice>();
            IStore      store        = forkChoice.GetGenesisStore(state);
            BeaconState genesisState = BeaconState.Clone(state);

            // block at slot 1
            BeaconState block1State = BeaconState.Clone(genesisState);
            BeaconBlock block1      = TestBlock.BuildEmptyBlockForNextSlot(testServiceProvider, block1State, signed: true);

            TestState.StateTransitionAndSignBlock(testServiceProvider, block1State, block1);
            await AddBlockToStore(testServiceProvider, store, block1);

            Hash32 block1Root = cryptographyService.SigningRoot(block1);

            // build short tree
            BeaconState block2State = BeaconState.Clone(genesisState);
            BeaconBlock block2      = TestBlock.BuildEmptyBlockForNextSlot(testServiceProvider, block2State, signed: true);

            block2.Body.SetGraffiti(new Bytes32(Enumerable.Repeat((byte)0x42, 32).ToArray()));
            TestBlock.SignBlock(testServiceProvider, block2State, block2, ValidatorIndex.None);
            TestState.StateTransitionAndSignBlock(testServiceProvider, block2State, block2);
            await AddBlockToStore(testServiceProvider, store, block2);

            Hash32 block2Root = cryptographyService.SigningRoot(block2);

            // Act
            Hash32 headRoot = await forkChoice.GetHeadAsync(store);

            // Assert
            Console.WriteLine("block1 {0}", block1Root);
            Console.WriteLine("block2 {0}", block2Root);
            Hash32 highestRoot = block1Root.CompareTo(block2Root) > 0 ? block1Root : block2Root;

            Console.WriteLine("highest {0}", highestRoot);
            headRoot.ShouldBe(highestRoot);
        }
Exemple #8
0
        public async Task SplitTieBreakerNoAttestations()
        {
            // Arrange
            IServiceProvider testServiceProvider = TestSystem.BuildTestServiceProvider(useStore: true);
            BeaconState      state = TestState.PrepareTestState(testServiceProvider);

            // Initialization
            ICryptographyService cryptographyService = testServiceProvider.GetService <ICryptographyService>();
            IForkChoice          forkChoice          = testServiceProvider.GetService <IForkChoice>();
            IStore store = testServiceProvider.GetService <IStore>();
            await forkChoice.InitializeForkChoiceStoreAsync(store, state);

            BeaconState genesisState = BeaconState.Clone(state);

            // block at slot 1
            BeaconState       block1State  = BeaconState.Clone(genesisState);
            BeaconBlock       block1       = TestBlock.BuildEmptyBlockForNextSlot(testServiceProvider, block1State, BlsSignature.Zero);
            SignedBeaconBlock signedBlock1 = TestState.StateTransitionAndSignBlock(testServiceProvider, block1State, block1);

            await AddBlockToStore(testServiceProvider, store, signedBlock1);

            Root block1Root = cryptographyService.HashTreeRoot(block1);

            // build short tree
            BeaconState block2State = BeaconState.Clone(genesisState);
            BeaconBlock block2      = TestBlock.BuildEmptyBlockForNextSlot(testServiceProvider, block2State, BlsSignature.Zero);

            block2.Body.SetGraffiti(new Bytes32(Enumerable.Repeat((byte)0x42, 32).ToArray()));
            TestBlock.SignBlock(testServiceProvider, block2State, block2, ValidatorIndex.None);
            SignedBeaconBlock signedBlock2 = TestState.StateTransitionAndSignBlock(testServiceProvider, block2State, block2);

            await AddBlockToStore(testServiceProvider, store, signedBlock2);

            Root block2Root = cryptographyService.HashTreeRoot(block2);

            // Act
            Root headRoot = await forkChoice.GetHeadAsync(store);

            // Assert
            Console.WriteLine("block1 {0}", block1Root);
            Console.WriteLine("block2 {0}", block2Root);
            Root highestRoot = block1Root.CompareTo(block2Root) > 0 ? block1Root : block2Root;

            Console.WriteLine("highest {0}", highestRoot);
            headRoot.ShouldBe(highestRoot);
        }
        public async Task InitializeForkChoiceStoreAsync(IStore store, BeaconState anchorState)
        {
            // Implements the logic for get_genesis_store / get_forkchoice_store

            Root stateRoot = !anchorState.LatestBlockHeader.StateRoot.Equals(Root.Zero)
                ? anchorState.LatestBlockHeader.StateRoot
                : _cryptographyService.HashTreeRoot(anchorState);

            BeaconBlock anchorBlock = new BeaconBlock(anchorState.Slot, anchorState.LatestBlockHeader.ParentRoot,
                                                      stateRoot, BeaconBlockBody.Zero);
            SignedBeaconBlock signedAnchorBlock = new SignedBeaconBlock(anchorBlock, BlsSignature.Zero);

            Root       anchorRoot          = _cryptographyService.HashTreeRoot(anchorBlock);
            Epoch      anchorEpoch         = _beaconStateAccessor.GetCurrentEpoch(anchorState);
            Checkpoint justifiedCheckpoint = new Checkpoint(anchorEpoch, anchorRoot);
            Checkpoint finalizedCheckpoint = new Checkpoint(anchorEpoch, anchorRoot);

            if (_logger.IsInfo())
            {
                Log.CreateGenesisStore(_logger, anchorState.Fork, anchorRoot, anchorState.GenesisTime, anchorState,
                                       anchorBlock, justifiedCheckpoint, null);
            }

            Dictionary <Root, SignedBeaconBlock> signedBlocks = new Dictionary <Root, SignedBeaconBlock>
            {
                [anchorRoot] = signedAnchorBlock
            };
            Dictionary <Root, BeaconState> blockStates = new Dictionary <Root, BeaconState>
            {
                [anchorRoot] = BeaconState.Clone(anchorState)
            };
            Dictionary <Checkpoint, BeaconState> checkpointStates = new Dictionary <Checkpoint, BeaconState>
            {
                [justifiedCheckpoint] = BeaconState.Clone(anchorState)
            };

            await store.InitializeForkChoiceStoreAsync(
                anchorState.GenesisTime,
                anchorState.GenesisTime,
                justifiedCheckpoint,
                finalizedCheckpoint,
                justifiedCheckpoint,
                signedBlocks,
                blockStates,
                checkpointStates);
        }
Exemple #10
0
        public IStore GetGenesisStore(BeaconState genesisState)
        {
            MiscellaneousParameters miscellaneousParameters = _miscellaneousParameterOptions.CurrentValue;
            MaxOperationsPerBlock   maxOperationsPerBlock   = _maxOperationsPerBlockOptions.CurrentValue;

            Hash32      stateRoot    = _cryptographyService.HashTreeRoot(genesisState);
            BeaconBlock genesisBlock = new BeaconBlock(stateRoot);

            Hash32 root = _cryptographyService.SigningRoot(genesisBlock);

            Checkpoint justifiedCheckpoint = new Checkpoint(_initialValueOptions.CurrentValue.GenesisEpoch, root);
            Checkpoint finalizedCheckpoint = new Checkpoint(_initialValueOptions.CurrentValue.GenesisEpoch, root);

            if (_logger.IsInfo())
            {
                Log.CreateGenesisStore(_logger, genesisBlock, genesisState, justifiedCheckpoint, root, null);
            }

            Dictionary <Hash32, BeaconBlock> blocks = new Dictionary <Hash32, BeaconBlock>
            {
                [root] = genesisBlock
            };
            Dictionary <Hash32, BeaconState> blockStates = new Dictionary <Hash32, BeaconState>
            {
                [root] = BeaconState.Clone(genesisState)
            };
            Dictionary <Checkpoint, BeaconState> checkpointStates = new Dictionary <Checkpoint, BeaconState>
            {
                [justifiedCheckpoint] = BeaconState.Clone(genesisState)
            };

            IStore store = _storeProvider.CreateStore(
                genesisState.GenesisTime,
                genesisState.GenesisTime,
                justifiedCheckpoint,
                finalizedCheckpoint,
                justifiedCheckpoint,
                blocks,
                blockStates,
                checkpointStates,
                new Dictionary <ValidatorIndex, LatestMessage>()
                );

            return(store);
        }
Exemple #11
0
        public IStore GetGenesisStore(BeaconState genesisState)
        {
            var miscellaneousParameters = _miscellaneousParameterOptions.CurrentValue;
            var maxOperationsPerBlock   = _maxOperationsPerBlockOptions.CurrentValue;

            var stateRoot           = genesisState.HashTreeRoot(miscellaneousParameters, _timeParameterOptions.CurrentValue, _stateListLengthOptions.CurrentValue, maxOperationsPerBlock);
            var genesisBlock        = new BeaconBlock(stateRoot);
            var root                = genesisBlock.SigningRoot(miscellaneousParameters, maxOperationsPerBlock);
            var justifiedCheckpoint = new Checkpoint(_initialValueOptions.CurrentValue.GenesisEpoch, root);
            var finalizedCheckpoint = new Checkpoint(_initialValueOptions.CurrentValue.GenesisEpoch, root);

            _logger.LogInformation(Event.CreateGenesisStore, "Creating genesis store with block {BeaconBlock} for state {BeaconState}, with checkpoint {JustifiedCheckpoint}, with signing root {SigningRoot}",
                                   genesisBlock, genesisState, justifiedCheckpoint, root);

            var blocks = new Dictionary <Hash32, BeaconBlock>
            {
                [root] = genesisBlock
            };
            var blockStates = new Dictionary <Hash32, BeaconState>
            {
                [root] = BeaconState.Clone(genesisState)
            };
            var checkpointStates = new Dictionary <Checkpoint, BeaconState>
            {
                [justifiedCheckpoint] = BeaconState.Clone(genesisState)
            };

            var store = _storeProvider.CreateStore(
                genesisState.GenesisTime,
                genesisState.GenesisTime,
                justifiedCheckpoint,
                finalizedCheckpoint,
                justifiedCheckpoint,
                blocks,
                blockStates,
                checkpointStates,
                new Dictionary <ValidatorIndex, LatestMessage>()
                );

            return(store);
        }
Exemple #12
0
        public void GenesisEpochNoAttestationsNoPenalties()
        {
            // Arrange
            IServiceProvider testServiceProvider = TestSystem.BuildTestServiceProvider();
            BeaconState      state = TestState.PrepareTestState(testServiceProvider);

            InitialValues      initialValues      = testServiceProvider.GetService <IOptions <InitialValues> >().Value;
            BeaconChainUtility beaconChainUtility = testServiceProvider.GetService <BeaconChainUtility>();

            BeaconState preState = BeaconState.Clone(state);

            Epoch stateEpoch = beaconChainUtility.ComputeEpochAtSlot(state.Slot);

            stateEpoch.ShouldBe(initialValues.GenesisEpoch);

            // Act
            RunProcessRewardsAndPenalties(testServiceProvider, state);

            // Assert
            for (int index = 0; index < preState.Validators.Count; index++)
            {
                state.Balances[index].ShouldBe(preState.Balances[index], $"Balance {index}");
            }
        }
Exemple #13
0
        public async Task OnBlockAsync(IStore store, BeaconBlock block)
        {
            MiscellaneousParameters miscellaneousParameters = _miscellaneousParameterOptions.CurrentValue;
            MaxOperationsPerBlock   maxOperationsPerBlock   = _maxOperationsPerBlockOptions.CurrentValue;

            Hash32 signingRoot = _cryptographyService.SigningRoot(block);

            if (_logger.IsInfo())
            {
                Log.OnBlock(_logger, signingRoot, block, null);
            }

            // Make a copy of the state to avoid mutability issues
            BeaconState parentState = await store.GetBlockStateAsync(block.ParentRoot).ConfigureAwait(false);

            BeaconState preState = BeaconState.Clone(parentState);

            // Blocks cannot be in the future. If they are, their consideration must be delayed until the are in the past.
            ulong blockTime = preState.GenesisTime + (ulong)block.Slot * _timeParameterOptions.CurrentValue.SecondsPerSlot;

            if (blockTime > store.Time)
            {
                throw new ArgumentOutOfRangeException(nameof(block), blockTime, $"Block slot time cannot be in the future, compared to store time {store.Time}.");
            }

            // Add new block to the store
            await store.SetBlockAsync(signingRoot, block).ConfigureAwait(false);

            // Check block is a descendant of the finalized block
            BeaconBlock finalizedCheckpointBlock = await store.GetBlockAsync(store.FinalizedCheckpoint.Root).ConfigureAwait(false);

            Hash32 ancestor = await GetAncestorAsync(store, signingRoot, finalizedCheckpointBlock !.Slot).ConfigureAwait(false);

            if (ancestor != store.FinalizedCheckpoint.Root)
            {
                throw new Exception($"Block with signing root {signingRoot} is not a descendant of the finalized block {store.FinalizedCheckpoint.Root} at slot {finalizedCheckpointBlock.Slot}.");
            }

            // Check that block is later than the finalized epoch slot
            Slot finalizedEpochStartSlot = _beaconChainUtility.ComputeStartSlotOfEpoch(store.FinalizedCheckpoint.Epoch);

            if (block.Slot <= finalizedEpochStartSlot)
            {
                throw new ArgumentOutOfRangeException(nameof(block), block.Slot, $"Block slot must be later than the finalized epoch start slot {finalizedEpochStartSlot}.");
            }

            // Check the block is valid and compute the post-state
            BeaconState state = _beaconStateTransition.StateTransition(preState, block, validateStateRoot: true);

            // Add new state for this block to the store
            await store.SetBlockStateAsync(signingRoot, state).ConfigureAwait(false);

            if (_logger.IsDebug())
            {
                LogDebug.AddedBlockToStore(_logger, block, state, signingRoot, null);
            }

            // Update justified checkpoint
            if (state.CurrentJustifiedCheckpoint.Epoch > store.JustifiedCheckpoint.Epoch)
            {
                await store.SetBestJustifiedCheckpointAsync(state.CurrentJustifiedCheckpoint).ConfigureAwait(false);

                bool shouldUpdateJustifiedCheckpoint = await ShouldUpdateJustifiedCheckpointAsync(store, state.CurrentJustifiedCheckpoint).ConfigureAwait(false);

                if (shouldUpdateJustifiedCheckpoint)
                {
                    await store.SetJustifiedCheckpointAsync(state.CurrentJustifiedCheckpoint).ConfigureAwait(false);

                    if (_logger.IsDebug())
                    {
                        LogDebug.UpdateJustifiedCheckpoint(_logger, state.CurrentJustifiedCheckpoint, null);
                    }
                }
                else
                {
                    if (_logger.IsDebug())
                    {
                        LogDebug.UpdateBestJustifiedCheckpoint(_logger, state.CurrentJustifiedCheckpoint, null);
                    }
                }
            }

            // Update finalized checkpoint
            if (state.FinalizedCheckpoint.Epoch > store.FinalizedCheckpoint.Epoch)
            {
                await store.SetFinalizedCheckpointAsync(state.FinalizedCheckpoint).ConfigureAwait(false);

                if (_logger.IsDebug())
                {
                    LogDebug.UpdateFinalizedCheckpoint(_logger, state.FinalizedCheckpoint, null);
                }
            }
        }
        /// <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);
                }
            }
        }
Exemple #15
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);
        }
Exemple #16
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 attestationBlock))
            {
                throw new ArgumentOutOfRangeException("attestation.Data.BeaconBlockRoot", attestation.Data.BeaconBlockRoot, "Attestation data root not found in the block history.");
            }
            // 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($"Ättestation 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;
            var 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)
                {
                    var newLatestMessage = new LatestMessage(target.Epoch, attestation.Data.BeaconBlockRoot);
                    store.SetLatestMessage(index, newLatestMessage);
                }
            }
        }
Exemple #17
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);
        }
Exemple #18
0
        public void OnBlock(IStore store, BeaconBlock block)
        {
            // Make a copy of the state to avoid mutability issues
            if (!store.TryGetBlockState(block.ParentRoot, out BeaconState? parentState) || parentState is null)
            {
                throw new ArgumentOutOfRangeException(nameof(block), block.ParentRoot, "Block parent root not found in the block states history.");
            }

            var preState = BeaconState.Clone(parentState);

            // Blocks cannot be in the future. If they are, their consideration must be delayed until the are in the past.
            var blockTime = preState.GenesisTime + (ulong)block.Slot * _timeParameterOptions.CurrentValue.SecondsPerSlot;

            if (blockTime > store.Time)
            {
                throw new ArgumentOutOfRangeException(nameof(block), blockTime, $"Block slot time cannot be in the future, compared to store time {store.Time}.");
            }

            // Add new block to the store
            var signingRoot = block.SigningRoot(_miscellaneousParameterOptions.CurrentValue, _maxOperationsPerBlockOptions.CurrentValue);

            store.SetBlock(signingRoot, block);

            // Check block is a descendant of the finalized block
            if (!store.TryGetBlock(store.FinalizedCheckpoint.Root, out var finalizedCheckpointBlock))
            {
                throw new Exception($"Block not found for finalized checkpoint root {store.FinalizedCheckpoint.Root}.");
            }

            Hash32 ancestor = GetAncestor(store, signingRoot, finalizedCheckpointBlock !.Slot);

            if (ancestor != store.FinalizedCheckpoint.Root)
            {
                throw new Exception($"Block with signing root {signingRoot} is not a descendant of the finalized block {store.FinalizedCheckpoint.Root} at slot {finalizedCheckpointBlock.Slot}.");
            }

            // Check that block is later than the finalized epoch slot
            var finalizedEpochStartSlot = _beaconChainUtility.ComputeStartSlotOfEpoch(store.FinalizedCheckpoint.Epoch);

            if (block.Slot <= finalizedEpochStartSlot)
            {
                throw new ArgumentOutOfRangeException(nameof(block), block.Slot, $"Block slot must be later than the finalized epoch start slot {finalizedEpochStartSlot}.");
            }

            // Check the block is valid and compute the post-state
            var state = _beaconStateTransition.StateTransition(preState, block, validateStateRoot: true);

            // Add new state for this block to the store
            store.SetBlockState(signingRoot, state);

            _logger.LogInformation(Event.CreateGenesisStore, "Store added block {BeaconBlock} generating state {BeaconState}, with signing root {SigningRoot}",
                                   block, state, signingRoot);

            // Update justified checkpoint
            if (state.CurrentJustifiedCheckpoint.Epoch > store.JustifiedCheckpoint.Epoch)
            {
                store.SetBestJustifiedCheckpoint(state.CurrentJustifiedCheckpoint);
                var shouldUpdateJustifiedCheckpoint = ShouldUpdateJustifiedCheckpoint(store, state.CurrentJustifiedCheckpoint);
                if (shouldUpdateJustifiedCheckpoint)
                {
                    store.SetJustifiedCheckpoint(state.CurrentJustifiedCheckpoint);
                    _logger.LogDebug("Updated justified checkpoint {JustifiedCheckpoint}", state.CurrentJustifiedCheckpoint);
                }
                else
                {
                    _logger.LogDebug("Updated best justified checkpoint {JustifiedCheckpoint}", state.CurrentJustifiedCheckpoint);
                }
            }

            // Update finalized checkpoint
            if (state.FinalizedCheckpoint.Epoch > store.FinalizedCheckpoint.Epoch)
            {
                store.SetFinalizedCheckpoint(state.FinalizedCheckpoint);
                _logger.LogDebug("Updated finalized checkpoint {FinalizedCheckpoint}", state.FinalizedCheckpoint);
            }
        }
        public async Task OnBlockAsync(IStore store, SignedBeaconBlock signedBlock)
        {
            MiscellaneousParameters miscellaneousParameters = _miscellaneousParameterOptions.CurrentValue;
            MaxOperationsPerBlock   maxOperationsPerBlock   = _maxOperationsPerBlockOptions.CurrentValue;

            BeaconBlock block     = signedBlock.Message;
            Root        blockRoot = _cryptographyService.HashTreeRoot(block);

            if (_logger.IsInfo())
            {
                Log.OnBlock(_logger, blockRoot, block, signedBlock.Signature, null);
            }

            // Make a copy of the state to avoid mutability issues
            BeaconState parentState = await store.GetBlockStateAsync(block.ParentRoot).ConfigureAwait(false);

            BeaconState preState = BeaconState.Clone(parentState);

            // Blocks cannot be in the future. If they are, their consideration must be delayed until the are in the past.
            ulong storeTime        = store.Time;
            Slot  storeCurrentSlot = GetCurrentSlot(store);

            if (storeCurrentSlot < block.Slot)
            {
                throw new ArgumentOutOfRangeException(nameof(block), block.Slot,
                                                      $"Block slot time cannot be in the future, compared to store time {storeTime} (slot {storeCurrentSlot}, since genesis {store.GenesisTime}.");
            }

            // Add new block to the store
            await store.SetSignedBlockAsync(blockRoot, signedBlock).ConfigureAwait(false);

            // Check that block is later than the finalized epoch slot (optimization to reduce calls to get_ancestor)
            Slot finalizedSlot = _beaconChainUtility.ComputeStartSlotOfEpoch(store.FinalizedCheckpoint.Epoch);

            if (block.Slot <= finalizedSlot)
            {
                throw new ArgumentOutOfRangeException(nameof(block), block.Slot,
                                                      $"Block slot must be later than the finalized epoch start slot {finalizedSlot}.");
            }

            // Check block is a descendant of the finalized block at the checkpoint finalized slot
            Root ancestorOfBlockAtFinalizedSlot =
                await GetAncestorAsync(store, blockRoot, finalizedSlot).ConfigureAwait(false);

            if (!ancestorOfBlockAtFinalizedSlot.Equals(store.FinalizedCheckpoint.Root))
            {
                throw new Exception(
                          $"Block with hash tree root {blockRoot} is not a descendant of the finalized block {store.FinalizedCheckpoint.Root} at slot {finalizedSlot}.");
            }

            // Check the block is valid and compute the post-state
            BeaconState state = _beaconStateTransition.StateTransition(preState, signedBlock, validateResult: true);

            // Add new state for this block to the store
            await store.SetBlockStateAsync(blockRoot, state).ConfigureAwait(false);

            if (_logger.IsDebug())
            {
                LogDebug.AddedBlockToStore(_logger, block, state, blockRoot, null);
            }

            // Update justified checkpoint
            if (state.CurrentJustifiedCheckpoint.Epoch > store.JustifiedCheckpoint.Epoch)
            {
                if (state.CurrentJustifiedCheckpoint.Epoch > store.BestJustifiedCheckpoint.Epoch)
                {
                    await store.SetBestJustifiedCheckpointAsync(state.CurrentJustifiedCheckpoint).ConfigureAwait(false);
                }

                bool shouldUpdateJustifiedCheckpoint =
                    await ShouldUpdateJustifiedCheckpointAsync(store, state.CurrentJustifiedCheckpoint)
                    .ConfigureAwait(false);

                if (shouldUpdateJustifiedCheckpoint)
                {
                    await store.SetJustifiedCheckpointAsync(state.CurrentJustifiedCheckpoint).ConfigureAwait(false);

                    if (_logger.IsDebug())
                    {
                        LogDebug.UpdateJustifiedCheckpoint(_logger, state.CurrentJustifiedCheckpoint, null);
                    }
                }
                else
                {
                    if (_logger.IsDebug())
                    {
                        LogDebug.UpdateBestJustifiedCheckpoint(_logger, state.CurrentJustifiedCheckpoint, null);
                    }
                }
            }

            // Update finalized checkpoint
            if (state.FinalizedCheckpoint.Epoch > store.FinalizedCheckpoint.Epoch)
            {
                await store.SetFinalizedCheckpointAsync(state.FinalizedCheckpoint).ConfigureAwait(false);

                if (_logger.IsDebug())
                {
                    LogDebug.UpdateFinalizedCheckpoint(_logger, state.FinalizedCheckpoint, null);
                }

                // Update justified if new justified is later than store justified
                // or if store justified is not in chain with finalized checkpoint
                if (state.CurrentJustifiedCheckpoint.Epoch > store.JustifiedCheckpoint.Epoch)
                {
                    await store.SetJustifiedCheckpointAsync(state.CurrentJustifiedCheckpoint).ConfigureAwait(false);

                    if (_logger.IsDebug())
                    {
                        LogDebug.UpdateJustifiedCheckpoint(_logger, state.CurrentJustifiedCheckpoint, null);
                    }
                }
                else
                {
                    Slot newFinalizedSlot =
                        _beaconChainUtility.ComputeStartSlotOfEpoch(store.FinalizedCheckpoint.Epoch);
                    Root ancestorOfJustifiedAtNewFinalizedSlot =
                        await GetAncestorAsync(store, store.JustifiedCheckpoint.Root, newFinalizedSlot)
                        .ConfigureAwait(false);

                    if (!ancestorOfJustifiedAtNewFinalizedSlot.Equals(store.FinalizedCheckpoint.Root))
                    {
                        await store.SetJustifiedCheckpointAsync(state.CurrentJustifiedCheckpoint).ConfigureAwait(false);

                        if (_logger.IsDebug())
                        {
                            LogDebug.UpdateJustifiedCheckpoint(_logger, state.CurrentJustifiedCheckpoint, null);
                        }
                    }
                }
            }
        }
Exemple #20
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());
        }
        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);
        }