Exemplo n.º 1
0
        public override Empty FirstRound(Round input)
        {
            if (State.CurrentRoundNumber.Value != 0)
            {
                return(new Empty());
            }
            Assert(input.RoundNumber == 1, "Invalid round number.");
            Assert(input.RealTimeMinersInformation.Any(), "No miner in input data.");

            State.CurrentTermNumber.Value       = 1;
            State.CurrentRoundNumber.Value      = 1;
            State.FirstRoundNumberOfEachTerm[1] = 1L;
            SetBlockchainStartTimestamp(input.GetStartTime());
            State.MiningInterval.Value = input.GetMiningInterval();

            var minerList = new MinerList
            {
                Pubkeys = { input.RealTimeMinersInformation.Keys.Select(k => k.ToByteString()) }
            };

            State.MainChainCurrentMinerList.Value = minerList;

            SetMinerList(minerList, 1);

            Assert(TryToAddRoundInformation(input), "Failed to add round information.");

            Context.LogDebug(() =>
                             $"Initial Miners: {input.RealTimeMinersInformation.Keys.Aggregate("\n", (key1, key2) => key1 + "\n" + key2)}");

            return(new Empty());
        }
        /// <summary>
        /// Only Main Chain can perform this action.
        /// </summary>
        /// <param name="minerList"></param>
        /// <param name="termNumber"></param>
        /// <param name="gonnaReplaceSomeone"></param>
        /// <returns></returns>
        private bool SetMinerList(MinerList minerList, long termNumber, bool gonnaReplaceSomeone = false)
        {
            // Miners for one specific term should only update once.
            var minerListFromState = State.MinerListMap[termNumber];
            if (gonnaReplaceSomeone || minerListFromState == null)
            {
                State.MainChainCurrentMinerList.Value = minerList;
                State.MinerListMap[termNumber] = minerList;
                return true;
            }

            return false;
        }
Exemplo n.º 3
0
        internal static Round GenerateFirstRoundOfNewTerm(this MinerList miners, int miningInterval,
                                                          Timestamp currentBlockTime, long currentRoundNumber = 0, long currentTermNumber = 0)
        {
            var sortedMiners =
                (from obj in miners.Pubkeys.Distinct()
                 .ToDictionary <ByteString, string, int>(miner => miner.ToHex(), miner => miner[0])
                 orderby obj.Value descending
                 select obj.Key).ToList();

            var round = new Round();

            for (var i = 0; i < sortedMiners.Count; i++)
            {
                var minerInRound = new MinerInRound();

                // The first miner will be the extra block producer of first round of each term.
                if (i == 0)
                {
                    minerInRound.IsExtraBlockProducer = true;
                }

                minerInRound.Pubkey             = sortedMiners[i];
                minerInRound.Order              = i + 1;
                minerInRound.ExpectedMiningTime =
                    currentBlockTime.AddMilliseconds((i * miningInterval) + miningInterval);
                // Should be careful during validation.
                minerInRound.PreviousInValue = Hash.Empty;

                round.RealTimeMinersInformation.Add(sortedMiners[i], minerInRound);
            }

            round.RoundNumber            = currentRoundNumber + 1;
            round.TermNumber             = currentTermNumber + 1;
            round.IsMinerListJustChanged = true;

            return(round);
        }
Exemplo n.º 4
0
        private void ProcessNextTerm(Round nextRound)
        {
            RecordMinedMinerListOfCurrentRound();

            // 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(nextRound.TermNumber), "Failed to update term number.");
            Assert(TryToUpdateRoundNumber(nextRound.RoundNumber), "Failed to update round number.");

            UpdateMinersCountToElectionContract(nextRound);

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

            UpdateProducedBlocksNumberOfSender(nextRound);

            // Update miners list.
            var miners = new MinerList();

            miners.Pubkeys.AddRange(nextRound.RealTimeMinersInformation.Keys.Select(k => k.ToByteString()));
            if (!SetMinerList(miners, nextRound.TermNumber))
            {
                Assert(false, "Failed to update miner list.");
            }

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

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

            if (!TryToGetPreviousRoundInformation(out var previousRound))
            {
                Assert(false, "Failed to get previous round information.");
            }

            UpdateCurrentMinerInformationToElectionContract(previousRound);

            DonateMiningReward(previousRound);

            State.TreasuryContract.Release.Send(new ReleaseInput
            {
                TermNumber = termNumber
            });

            Context.LogDebug(() => $"Released treasury profit for term {termNumber}");

            State.ElectionContract.TakeSnapshot.Send(new TakeElectionSnapshotInput
            {
                MinedBlocks = previousRound.GetMinedBlocks(),
                TermNumber  = termNumber,
                RoundNumber = previousRound.RoundNumber
            });

            Context.LogDebug(() => $"Changing term number to {nextRound.TermNumber}");
        }