Example #1
0
 private void AddOrUpdateMinerHistoryInformation(CandidateInHistory historyInformation)
 {
     State.HistoryMap[historyInformation.PublicKey.ToStringValue()] = historyInformation;
 }
Example #2
0
        private ActionResult SnapshotForMiners(TermInfo input)
        {
            var lastRoundNumber    = input.RoundNumber;
            var previousTermNumber = input.TermNumber;

            Assert(TryToGetRoundInformation(lastRoundNumber, out var roundInformation),
                   "Round information not found.");

            foreach (var candidate in roundInformation.RealTimeMinersInformation)
            {
                CandidateInHistory candidateInHistory;
                if (TryToGetMinerHistoryInformation(candidate.Key, out var historyInformation))
                {
                    var terms = new List <long>(historyInformation.Terms.ToList());

                    if (terms.Contains(previousTermNumber))
                    {
                        return(new ActionResult
                        {
                            Success = false, ErrorMessage = "Snapshot for miners in previous term already taken."
                        });
                    }

                    terms.Add(previousTermNumber);

                    var continualAppointmentCount = historyInformation.ContinualAppointmentCount;
                    if (TryToGetMiners(previousTermNumber, out var minersOfLastTerm) &&
                        minersOfLastTerm.PublicKeys.Contains(candidate.Key))
                    {
                        continualAppointmentCount++;
                    }
                    else
                    {
                        continualAppointmentCount = 0;
                    }

                    candidateInHistory = new CandidateInHistory
                    {
                        PublicKey                 = candidate.Key,
                        MissedTimeSlots           = historyInformation.MissedTimeSlots + candidate.Value.MissedTimeSlots,
                        ProducedBlocks            = historyInformation.ProducedBlocks + candidate.Value.ProducedBlocks,
                        ContinualAppointmentCount = continualAppointmentCount,
                        ReappointmentCount        = historyInformation.ReappointmentCount + 1,
                        CurrentAlias              = historyInformation.CurrentAlias,
                        Terms = { terms }
                    };
                }
                else
                {
                    candidateInHistory = new CandidateInHistory
                    {
                        PublicKey                 = candidate.Key,
                        MissedTimeSlots           = candidate.Value.MissedTimeSlots,
                        ProducedBlocks            = candidate.Value.ProducedBlocks,
                        ContinualAppointmentCount = 0,
                        ReappointmentCount        = 0,
                        Terms = { previousTermNumber }
                    };
                }

                AddOrUpdateMinerHistoryInformation(candidateInHistory);
            }

            return(new ActionResult {
                Success = true
            });
        }
Example #3
0
 private bool TryToGetMinerHistoryInformation(string publicKey, out CandidateInHistory historyInformation)
 {
     historyInformation = State.HistoryMap[publicKey.ToStringValue()];
     return(historyInformation != null);
 }
Example #4
0
        public override Empty NextTerm(Round input)
        {
            // Count missed time slot of current round.
            CountMissedTimeSlots();

            Assert(TryToGetTermNumber(out var termNumber), "Term number not found.");

            // Update current term number and current round number.
            Assert(TryToUpdateTermNumber(input.TermNumber), "Failed to update term number.");
            Assert(TryToUpdateRoundNumber(input.RoundNumber), "Failed to update round number.");

            // Reset some fields of first two rounds of next term.
            foreach (var minerInRound in input.RealTimeMinersInformation.Values)
            {
                minerInRound.MissedTimeSlots = 0;
                minerInRound.ProducedBlocks  = 0;
            }

            var senderPublicKey = Context.RecoverPublicKey().ToHex();

            // Update produced block number of this node.
            if (input.RealTimeMinersInformation.ContainsKey(senderPublicKey))
            {
                input.RealTimeMinersInformation[senderPublicKey].ProducedBlocks += 1;
            }
            else
            {
                if (TryToGetMinerHistoryInformation(senderPublicKey, out var historyInformation))
                {
                    historyInformation.ProducedBlocks += 1;
                }
                else
                {
                    historyInformation = new CandidateInHistory
                    {
                        PublicKey      = senderPublicKey,
                        ProducedBlocks = 1,
                        CurrentAlias   = senderPublicKey.Substring(0, DPoSContractConsts.AliasLimit)
                    };
                }

                AddOrUpdateMinerHistoryInformation(historyInformation);
            }

            // Update miners list.
            Assert(SetMiners(input.RealTimeMinersInformation.Keys.ToList().ToMiners(input.TermNumber)),
                   ContractErrorCode.GetErrorMessage(ContractErrorCode.AttemptFailed, "Failed to update miners list."));

            // Update term number lookup. (Using term number to get first round number of related term.)
            State.TermToFirstRoundMap[input.TermNumber.ToInt64Value()] = input.RoundNumber.ToInt64Value();

            // Update blockchain age of new term.
            UpdateBlockchainAge(input.BlockchainAge);

            // Update rounds information of next two rounds.
            Assert(TryToAddRoundInformation(input), "Failed to add round information.");

            if (State.DividendContract.Value != null)
            {
                State.DividendContract.Value =
                    State.BasicContractZero.GetContractAddressByName.Call(State.DividendContractSystemName.Value);
                State.DividendContract.KeepWeights.Send(new SInt64Value {
                    Value = termNumber
                });

                var termInfo = new TermInfo
                {
                    RoundNumber = input.RoundNumber - 1,
                    TermNumber  = input.TermNumber - 1
                };
                Assert(SnapshotForTerm(termInfo).Success,
                       ContractErrorCode.GetErrorMessage(ContractErrorCode.AttemptFailed,
                                                         $"Failed to take snapshot of term {termInfo.TermNumber}"));
                Assert(SnapshotForMiners(termInfo).Success,
                       ContractErrorCode.GetErrorMessage(ContractErrorCode.AttemptFailed,
                                                         $"Failed to take snapshot of miners of term {termInfo.TermNumber}"));
                Assert(SendDividends(termInfo).Success,
                       ContractErrorCode.GetErrorMessage(ContractErrorCode.AttemptFailed,
                                                         $"Failed to send dividends of term {termInfo.TermNumber}"));
            }

            Context.LogDebug(() => $"Changing term number to {input.TermNumber}");
            TryToFindLIB();
            return(new Empty());
        }