private async Task CheckCommitAsync(ViewChangeCommitMessage vcm) { if (!commitMsgs.ContainsKey(vcm.From)) { var cmt = new VCCommitWithTime(vcm); commitMsgs.AddOrUpdate(vcm.From, cmt, (key, oldValue) => cmt); await CheckAllStatsAsync(); } }
public VCCommitWithTime(ViewChangeCommitMessage 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); } } } }