public Round RecoverFromUpdateValue(Round providedRound, string pubkey) { if (!RealTimeMinersInformation.ContainsKey(pubkey) || !providedRound.RealTimeMinersInformation.ContainsKey(pubkey)) { return(this); } var minerInRound = RealTimeMinersInformation[pubkey]; var providedInformation = providedRound.RealTimeMinersInformation[pubkey]; minerInRound.OutValue = providedInformation.OutValue; minerInRound.Signature = providedInformation.Signature; minerInRound.ProducedBlocks = providedInformation.ProducedBlocks; minerInRound.ProducedTinyBlocks = providedInformation.ProducedTinyBlocks; minerInRound.PreviousInValue = providedInformation.PreviousInValue; minerInRound.ImpliedIrreversibleBlockHeight = providedInformation.ImpliedIrreversibleBlockHeight; minerInRound.ActualMiningTimes.Add(providedInformation.ActualMiningTimes); foreach (var information in providedRound.RealTimeMinersInformation) { RealTimeMinersInformation[information.Key].SupposedOrderOfNextRound = information.Value.SupposedOrderOfNextRound; RealTimeMinersInformation[information.Key].FinalOrderOfNextRound = information.Value.FinalOrderOfNextRound; RealTimeMinersInformation[information.Key].PreviousInValue = information.Value.PreviousInValue; } return(this); }
public bool IsTimeSlotPassed(string publicKey, Timestamp currentBlockTime) { var miningInterval = GetMiningInterval(); if (!RealTimeMinersInformation.ContainsKey(publicKey)) { return(false); } var minerInRound = RealTimeMinersInformation[publicKey]; if (RoundNumber != 1) { return(minerInRound.ExpectedMiningTime + new Duration { Seconds = miningInterval.Div(1000) } < currentBlockTime); } var actualStartTimes = FirstMiner().ActualMiningTimes; if (actualStartTimes.Count == 0) { return(false); } var actualStartTime = actualStartTimes.First(); var runningTime = currentBlockTime - actualStartTime; var expectedOrder = runningTime.Seconds.Div(miningInterval.Div(1000)).Add(1); return(minerInRound.Order < expectedOrder); }
public Timestamp GetExpectedMiningTime(string publicKey) { return(RealTimeMinersInformation.ContainsKey(publicKey) ? RealTimeMinersInformation[publicKey].ExpectedMiningTime : new Timestamp { Seconds = long.MaxValue }); }
internal bool IsTimeSlotPassed(string publicKey, DateTime dateTime, out MinerInRound minerInRound) { minerInRound = null; var miningInterval = GetMiningInterval(); if (!RealTimeMinersInformation.ContainsKey(publicKey)) { return(false); } minerInRound = RealTimeMinersInformation[publicKey]; return(minerInRound.ExpectedMiningTime.ToDateTime().AddMilliseconds(miningInterval) <= dateTime); }
public Round ApplyNormalConsensusData(string publicKey, Hash previousInValue, Hash outValue, Hash signature) { if (!RealTimeMinersInformation.ContainsKey(publicKey)) { return(this); } RealTimeMinersInformation[publicKey].OutValue = outValue; RealTimeMinersInformation[publicKey].Signature = signature; if (previousInValue != Hash.Empty) { RealTimeMinersInformation[publicKey].PreviousInValue = previousInValue; } var minersCount = RealTimeMinersInformation.Count; var sigNum = signature.ToInt64(); var supposedOrderOfNextRound = GetAbsModulus(sigNum, minersCount) + 1; // Check the existence of conflicts about OrderOfNextRound. // If so, modify others'. var conflicts = RealTimeMinersInformation.Values .Where(i => i.FinalOrderOfNextRound == supposedOrderOfNextRound).ToList(); foreach (var orderConflictedMiner in conflicts) { // Multiple conflicts is unlikely. for (var i = supposedOrderOfNextRound + 1; i < minersCount * 2; i++) { var maybeNewOrder = i > minersCount ? i % minersCount : i; if (RealTimeMinersInformation.Values.All(m => m.FinalOrderOfNextRound != maybeNewOrder)) { RealTimeMinersInformation[orderConflictedMiner.Pubkey].FinalOrderOfNextRound = maybeNewOrder; break; } } } RealTimeMinersInformation[publicKey].SupposedOrderOfNextRound = supposedOrderOfNextRound; // Initialize FinalOrderOfNextRound as the value of SupposedOrderOfNextRound RealTimeMinersInformation[publicKey].FinalOrderOfNextRound = supposedOrderOfNextRound; return(this); }
public Round RecoverFromTinyBlock(Round providedRound, string pubkey) { if (!RealTimeMinersInformation.ContainsKey(pubkey) || !providedRound.RealTimeMinersInformation.ContainsKey(pubkey)) { return(this); } var minerInRound = RealTimeMinersInformation[pubkey]; var providedInformation = providedRound.RealTimeMinersInformation[pubkey]; minerInRound.ProducedBlocks = providedInformation.ProducedBlocks; minerInRound.ProducedTinyBlocks = providedInformation.ProducedTinyBlocks; minerInRound.ImpliedIrreversibleBlockHeight = providedInformation.ImpliedIrreversibleBlockHeight; minerInRound.ActualMiningTimes.Add(providedInformation.ActualMiningTimes); return(this); }
/// <summary> /// If one node produced block this round or missed his time slot, /// whatever how long he missed, we can give him a consensus command with new time slot /// to produce a block (for terminating current round and start new round). /// The schedule generated by this command will be cancelled /// if this node executed blocks from other nodes. /// /// Notice: /// This method shouldn't return the expected mining time from round information. /// To prevent this kind of misuse, this method will return a invalid timestamp /// when this node hasn't missed his time slot. /// </summary> /// <returns></returns> public Timestamp ArrangeAbnormalMiningTime(string publicKey, DateTime dateTime, int miningInterval = 0) { if (!RealTimeMinersInformation.ContainsKey(publicKey)) { return(new Timestamp { Seconds = long.MaxValue });; } if (miningInterval == 0) { miningInterval = GetMiningInterval(); } if (!IsTimeSlotPassed(publicKey, dateTime, out var minerInRound) && minerInRound.OutValue == null) { return(new Timestamp { Seconds = long.MaxValue });; } if (GetExtraBlockProducerInformation().Pubkey == publicKey) { var distance = (GetExtraBlockMiningTime() - dateTime).TotalMilliseconds; if (distance > 0) { return(GetExtraBlockMiningTime().ToTimestamp()); } } if (RealTimeMinersInformation.ContainsKey(publicKey) && miningInterval > 0) { var distanceToRoundStartTime = (dateTime - GetStartTime()).TotalMilliseconds; var missedRoundsCount = (int)(distanceToRoundStartTime / TotalMilliseconds(miningInterval)); var expectedEndTime = GetExpectedEndTime(missedRoundsCount, miningInterval); return(expectedEndTime.ToDateTime().AddMilliseconds(minerInRound.Order * miningInterval).ToTimestamp()); } // Never do the mining if this node has no privilege to mime or the mining interval is invalid. return(new Timestamp { Seconds = long.MaxValue });; }
/// <summary> /// Maybe tune other miners' supposed order of next round, /// will record this purpose to their FinalOrderOfNextRound field. /// </summary> /// <param name="publicKey"></param> /// <returns></returns> public UpdateValueInput ExtractInformationToUpdateConsensus(string publicKey) { if (!RealTimeMinersInformation.ContainsKey(publicKey)) { return(null); } var minerInRound = RealTimeMinersInformation[publicKey]; var tuneOrderInformation = RealTimeMinersInformation.Values .Where(m => m.FinalOrderOfNextRound != m.SupposedOrderOfNextRound) .ToDictionary(m => m.Pubkey, m => m.FinalOrderOfNextRound); var decryptedPreviousInValues = RealTimeMinersInformation.Values.Where(v => v.Pubkey != publicKey && v.DecryptedPreviousInValues.ContainsKey(publicKey)) .ToDictionary(info => info.Pubkey, info => info.DecryptedPreviousInValues[publicKey]); var minersPreviousInValues = RealTimeMinersInformation.Values.Where(info => info.PreviousInValue != null).ToDictionary( info => info.Pubkey, info => info.PreviousInValue); return(new UpdateValueInput { OutValue = minerInRound.OutValue, Signature = minerInRound.Signature, PreviousInValue = minerInRound.PreviousInValue ?? Hash.Empty, RoundId = RoundId, ProducedBlocks = minerInRound.ProducedBlocks, ActualMiningTime = minerInRound.ActualMiningTimes.Last(), SupposedOrderOfNextRound = minerInRound.SupposedOrderOfNextRound, TuneOrderInformation = { tuneOrderInformation }, EncryptedInValues = { minerInRound.EncryptedInValues }, DecryptedPreviousInValues = { decryptedPreviousInValues }, MinersPreviousInValues = { minersPreviousInValues }, ImpliedIrreversibleBlockHeight = minerInRound.ImpliedIrreversibleBlockHeight }); }
/// <summary> /// Get miner's order of provided round information. /// If provided round doesn't contain this pubkey, return int.MaxValue. /// </summary> /// <param name="pubkey"></param> /// <returns></returns> public int GetMiningOrder(string pubkey) { return(RealTimeMinersInformation.ContainsKey(pubkey) ? RealTimeMinersInformation[pubkey].Order : int.MaxValue); }