Esempio n. 1
0
        private void OnBlockDisconnected(BlockDisconnected blockDisconnected)
        {
            ChainedHeaderBlock chBlock = blockDisconnected.DisconnectedBlock;

            lock (this.locker)
            {
                foreach (Poll poll in this.polls.Where(x => !x.IsPending && x.PollExecutedBlockData?.Hash == chBlock.ChainedHeader.HashBlock).ToList())
                {
                    this.logger.LogDebug("Reverting poll execution '{0}'.", poll);
                    this.pollResultExecutor.RevertChange(poll.VotingData);

                    poll.PollExecutedBlockData = null;
                    this.pollsRepository.UpdatePoll(poll);
                }
            }

            byte[] rawVotingData = this.votingDataEncoder.ExtractRawVotingData(chBlock.Block.Transactions[0]);

            if (rawVotingData == null)
            {
                this.logger.LogTrace("(-)[NO_VOTING_DATA]");
                return;
            }

            List <VotingData> votingDataList = this.votingDataEncoder.Decode(rawVotingData);

            votingDataList.Reverse();

            lock (this.locker)
            {
                foreach (VotingData votingData in votingDataList)
                {
                    // If the poll is pending, that's the one we want. There should be maximum 1 of these.
                    Poll targetPoll = this.polls.SingleOrDefault(x => x.VotingData == votingData && x.IsPending);

                    // Otherwise, get the most recent poll. There could currently be unlimited of these, though they're harmless.
                    if (targetPoll == null)
                    {
                        targetPoll = this.polls.Last(x => x.VotingData == votingData);
                    }

                    this.logger.LogDebug("Reverting poll voting in favor: '{0}'.", targetPoll);

                    if (targetPoll.PollVotedInFavorBlockData == new HashHeightPair(chBlock.ChainedHeader))
                    {
                        targetPoll.PollVotedInFavorBlockData = null;

                        this.pollsRepository.UpdatePoll(targetPoll);
                    }

                    // Pub key of a fed member that created voting data.
                    string fedMemberKeyHex = this.slotsManager.GetFederationMemberForTimestamp(chBlock.Block.Header.Time).PubKey.ToHex();

                    targetPoll.PubKeysHexVotedInFavor.Remove(fedMemberKeyHex);

                    if (targetPoll.PubKeysHexVotedInFavor.Count == 0)
                    {
                        this.polls.Remove(targetPoll);
                        this.pollsRepository.RemovePolls(targetPoll.Id);

                        this.logger.LogDebug("Poll with Id {0} was removed.", targetPoll.Id);
                    }
                }
            }
        }
Esempio n. 2
0
        private void OnBlockConnected(BlockConnected blockConnected)
        {
            ChainedHeaderBlock chBlock          = blockConnected.ConnectedBlock;
            uint256            newFinalizedHash = this.finalizedBlockInfo.GetFinalizedBlockInfo().Hash;

            lock (this.locker)
            {
                foreach (Poll poll in this.polls.Where(x => !x.IsPending && x.PollVotedInFavorBlockData.Hash == newFinalizedHash).ToList())
                {
                    this.logger.LogDebug("Applying poll '{0}'.", poll);
                    this.pollResultExecutor.ApplyChange(poll.VotingData);

                    poll.PollExecutedBlockData = new HashHeightPair(chBlock.ChainedHeader);
                    this.pollsRepository.UpdatePoll(poll);
                }
            }

            byte[] rawVotingData = this.votingDataEncoder.ExtractRawVotingData(chBlock.Block.Transactions[0]);

            if (rawVotingData == null)
            {
                this.logger.LogTrace("(-)[NO_VOTING_DATA]");
                return;
            }

            // Pub key of a fed member that created voting data.
            string fedMemberKeyHex = this.slotsManager.GetFederationMemberForTimestamp(chBlock.Block.Header.Time).PubKey.ToHex();

            List <VotingData> votingDataList = this.votingDataEncoder.Decode(rawVotingData);

            this.logger.LogDebug("Applying {0} voting data items included in a block by '{1}'.", votingDataList.Count, fedMemberKeyHex);

            lock (this.locker)
            {
                foreach (VotingData data in votingDataList)
                {
                    Poll poll = this.polls.SingleOrDefault(x => x.VotingData == data && x.IsPending);

                    if (poll == null)
                    {
                        poll = new Poll()
                        {
                            Id = this.pollsRepository.GetHighestPollId() + 1,
                            PollVotedInFavorBlockData = null,
                            PollExecutedBlockData     = null,
                            PollStartBlockData        = new HashHeightPair(chBlock.ChainedHeader),
                            VotingData             = data,
                            PubKeysHexVotedInFavor = new List <string>()
                            {
                                fedMemberKeyHex
                            }
                        };

                        this.polls.Add(poll);
                        this.pollsRepository.AddPolls(poll);

                        this.logger.LogDebug("New poll was created: '{0}'.", poll);
                    }
                    else if (!poll.PubKeysHexVotedInFavor.Contains(fedMemberKeyHex))
                    {
                        poll.PubKeysHexVotedInFavor.Add(fedMemberKeyHex);
                        this.pollsRepository.UpdatePoll(poll);

                        this.logger.LogDebug("Voted on existing poll: '{0}'.", poll);
                    }
                    else
                    {
                        this.logger.LogDebug("Fed member '{0}' already voted for this poll. Ignoring his vote. Poll: '{1}'.", fedMemberKeyHex, poll);
                    }

                    List <string> fedMembersHex = this.federationManager.GetFederationMembers().Select(x => x.PubKey.ToHex()).ToList();

                    // It is possible that there is a vote from a federation member that was deleted from the federation.
                    // Do not count votes from entities that are not active fed members.
                    int validVotesCount = poll.PubKeysHexVotedInFavor.Count(x => fedMembersHex.Contains(x));

                    int requiredVotesCount = (fedMembersHex.Count / 2) + 1;

                    this.logger.LogDebug("Fed members count: {0}, valid votes count: {1}, required votes count: {2}.", fedMembersHex.Count, validVotesCount, requiredVotesCount);

                    if (validVotesCount < requiredVotesCount)
                    {
                        continue;
                    }

                    poll.PollVotedInFavorBlockData = new HashHeightPair(chBlock.ChainedHeader);
                    this.pollsRepository.UpdatePoll(poll);
                }
            }
        }