コード例 #1
0
        /// <summary>
        /// two ways to begin view changing: either one third of all voters requested, or local requested.
        ///
        /// </summary>
        /// <returns></returns>
        internal async Task BeginChangeViewAsync(ViewChangeReason reason)
        {
            _log.LogInformation($"BeginChangeViewAsync: VID: {ViewId} 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}");

            _reason = reason;
            var lastSb = await _sys.Storage.GetLastServiceBlockAsync();

            if (lastSb == null)
            {
                // genesis?
                _log.LogCritical($"BeginChangeViewAsync has null service block. should not happend. error.");
                return;
            }

            _isViewChanging = true;

            ShiftView(lastSb.Height + 1);
            selectedSuccess = false;

            _log.LogInformation($"View change for ViewId {ViewId} begin at {TimeStarted}");

            CalculateLeaderCandidate();

            var lastCons = await _sys.Storage.GetLastConsolidationBlockAsync();

            var req = new ViewChangeRequestMessage
            {
                From             = _sys.PosWallet.AccountId,
                ViewID           = ViewId,
                prevViewID       = lastSb.Height,
                requestSignature = Signatures.GetSignature(_sys.PosWallet.PrivateKey,
                                                           $"{lastSb.Hash}|{lastCons.Hash}", _sys.PosWallet.AccountId),
            };

            _context.Send2P2pNetwork(req);
            await CheckRequestAsync(req);
        }
コード例 #2
0
        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);
                    }
                }
            }
        }