Esempio n. 1
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());
        }