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; }
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); }
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}"); }