private async Task CheckReplyAsync(ViewChangeReplyMessage reply) { //_log.LogInformation($"CheckReply for view {reply.ViewID} with Candidate {reply.Candidate.Shorten()} of {replyMsgs.Count}/{_context.Board.AllVoters.Count}"); if (reply.Result == Blocks.APIResultCodes.Success) { if (replyMsgs.ContainsKey(reply.From)) { //if (replyMsgs[reply.From].msg.Candidate != reply.Candidate) //{ // replyMsgs[reply.From] = new VCReplyWithTime(reply); // await CheckAllStatsAsync(); //} } else { if (replyMsgs.TryAdd(reply.From, new VCReplyWithTime(reply))) { await CheckAllStatsAsync(); } } } }
public VCReplyWithTime(ViewChangeReplyMessage Message) { msg = Message; }
private async Task CheckAllStatsAsync() { if (!IsViewChanging) { RemoveOutDatedMsgs(); if (reqMsgs.Count > _context.Board.AllVoters.Count - LyraGlobal.GetMajority(_context.Board.AllVoters.Count)) { var sb = new StringBuilder(); foreach (var msg in reqMsgs) { sb.Append($"{msg.Key.Shorten()}, "); } _log.LogInformation($"too many view change request, {sb.ToString()}. force into view change mode"); // too many view change request. force into view change mode await _context.GotViewChangeRequestAsync(ViewId, reqMsgs.Count); } return; } // request if (!replySent && reqMsgs.Count >= LyraGlobal.GetMajority(_context.Board.AllVoters.Count)) { _log.LogInformation($"CheckAllStats VID: {ViewId} Time: {TimeStarted} Req: {reqMsgs.Count} Reply: {replyMsgs.Count} Commit: {commitMsgs.Count} Votes {commitMsgs.Count}/{LyraGlobal.GetMajority(_context.Board.AllVoters.Count)}/{_context.Board.AllVoters.Count} Replyed: {replySent} Commited: {commitSent}"); if (string.IsNullOrEmpty(nextLeader)) { CalculateLeaderCandidate(); } var reply = new ViewChangeReplyMessage { From = _sys.PosWallet.AccountId, ViewID = ViewId, Result = Blocks.APIResultCodes.Success, Candidate = nextLeader }; _context.Send2P2pNetwork(reply); replySent = true; await CheckReplyAsync(reply); } if (!commitSent) { if (replyMsgs.Count >= LyraGlobal.GetMajority(_context.Board.AllVoters.Count)) { _log.LogInformation($"CheckAllStats VID: {ViewId} Time: {TimeStarted} Req: {reqMsgs.Count} Reply: {replyMsgs.Count} Commit: {commitMsgs.Count} Votes {commitMsgs.Count}/{LyraGlobal.GetMajority(_context.Board.AllVoters.Count)}/{_context.Board.AllVoters.Count} Replyed: {replySent} Commited: {commitSent}"); // reply // only if we have enough reply var decQr = from rep in replyMsgs.Values where rep.msg.Result == Blocks.APIResultCodes.Success group rep by rep.msg.Candidate into g select new { Candidate = g.Key, Count = g.Count() }; var decisions = decQr.OrderByDescending(x => x.Count).ToList(); var candidateQR = decisions.FirstOrDefault(); var sb = new StringBuilder(); sb.AppendLine($"Decisions for View ID: {ViewId}"); foreach (var x in decisions) { sb.AppendLine($"\t{x.Candidate.Shorten()}: {x.Count}"); } _log.LogInformation(sb.ToString()); if (candidateQR?.Count >= LyraGlobal.GetMajority(_context.Board.AllVoters.Count)) { var commit = new ViewChangeCommitMessage { From = _sys.PosWallet.AccountId, ViewID = ViewId, Candidate = candidateQR.Candidate, Consensus = ConsensusResult.Yea }; _context.Send2P2pNetwork(commit); commitSent = true; await CheckCommitAsync(commit); } else { //_log.LogInformation($"CheckAllStats, By ReplyMsgs, not commit, top candidate {candidateQR?.Candidate.Shorten()} has {candidateQR?.Count} votes"); } } } if (!selectedSuccess) { // commit var q = from rep in commitMsgs.Values group rep by rep.msg.Candidate into g select new { Candidate = g.Key, Count = g.Count() }; var candidate = q.OrderByDescending(x => x.Count).FirstOrDefault(); if (candidate != null) { if (nextLeader != candidate.Candidate) { _log.LogWarning($"Next Leader {nextLeader} not {candidate.Candidate}"); } nextLeader = candidate.Candidate; if (candidate?.Count >= LyraGlobal.GetMajority(_context.Board.AllVoters.Count)) { _log.LogInformation($"CheckAllStats, By CommitMsgs, leader selected {candidate.Candidate} with {candidate.Count} votes."); selectedSuccess = true; _leaderSelected(this, ViewId, candidate.Candidate, candidate.Count, _context.Board.AllVoters); } } } }