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