Beispiel #1
0
        private IConsensusInformationGenerationService GetConsensusInformationGenerationService(
            DPoSBehaviour behavior)
        {
            var information = new ConsensusControlInformation()
            {
                ConsensusCommand = new ConsensusCommand
                {
                    Hint = ByteString.CopyFrom(new DPoSHint
                    {
                        Behaviour = behavior
                    }.ToByteArray())
                }
            };

            return(new DPoSInformationGenerationService(_accountService, information, _smartContractAddressService,
                                                        _transactionReadOnlyExecutionService));
        }
Beispiel #2
0
        public static string GetLogs(this Round round, string publicKey, DPoSBehaviour behaviour)
        {
            var logs = new StringBuilder($"\n[Round {round.RoundNumber}](Round Id: {round.RoundId})[Term {round.TermNumber}]");

            foreach (var minerInRound in round.RealTimeMinersInformation.Values.OrderBy(m => m.Order))
            {
                var minerInformation = new StringBuilder("\n");
                minerInformation.Append($"[{minerInRound.PublicKey.Substring(0, 10)}]");
                minerInformation.Append(minerInRound.IsExtraBlockProducer ? "(Current EBP)" : "");
                minerInformation.AppendLine(minerInRound.PublicKey == publicKey
                    ? "(This Node)"
                    : "");
                minerInformation.AppendLine($"Order:\t {minerInRound.Order}");
                minerInformation.AppendLine(
                    $"Expect:\t {minerInRound.ExpectedMiningTime?.ToDateTime().ToUniversalTime():yyyy-MM-dd HH.mm.ss,ffffff}");
                minerInformation.AppendLine(
                    $"Actual:\t {minerInRound.ActualMiningTime?.ToDateTime().ToUniversalTime():yyyy-MM-dd HH.mm.ss,ffffff}");
                minerInformation.AppendLine($"Out:\t {minerInRound.OutValue?.ToHex()}");
                if (round.RoundNumber != 1)
                {
                    minerInformation.AppendLine($"PreIn:\t {minerInRound.PreviousInValue?.ToHex()}");
                }

                minerInformation.AppendLine($"Sig:\t {minerInRound.Signature?.ToHex()}");
                minerInformation.AppendLine($"Mine:\t {minerInRound.ProducedBlocks}");
                minerInformation.AppendLine($"Miss:\t {minerInRound.MissedTimeSlots}");
                minerInformation.AppendLine($"Proms:\t {minerInRound.PromisedTinyBlocks}");
                minerInformation.AppendLine($"NOrder:\t {minerInRound.FinalOrderOfNextRound}");

                logs.Append(minerInformation);
            }

            logs.AppendLine($"Recent behaviour: {behaviour.ToString()}");

            return(logs.ToString());
        }
Beispiel #3
0
        /// <summary>
        /// DPoS Behaviour is changeable in this method.
        /// It's the situation this miner should skip his time slot, more precisely.
        /// </summary>
        /// <param name="behaviour"></param>
        /// <param name="round"></param>
        /// <param name="publicKey"></param>
        /// <param name="dateTime"></param>
        /// <param name="isTimeSlotSkippable"></param>
        /// <returns></returns>
        public static ConsensusCommand GetConsensusCommand(this DPoSBehaviour behaviour, Round round, string publicKey,
                                                           DateTime dateTime, bool isTimeSlotSkippable)
        {
            var minerInRound       = round.RealTimeMinersInformation[publicKey];
            var miningInterval     = round.GetMiningInterval();
            var myOrder            = round.RealTimeMinersInformation[minerInRound.PublicKey].Order;
            var expectedMiningTime = round.RealTimeMinersInformation[minerInRound.PublicKey].ExpectedMiningTime;

            int nextBlockMiningLeftMilliseconds;
            var hint = new DPoSHint {
                Behaviour = behaviour
            }.ToByteString();

            var previousMinerMissedHisTimeSlot       = myOrder != 1 &&
                                                       round.RealTimeMinersInformation.Values
                                                       .First(m => m.Order == myOrder - 1).OutValue == null;
            var previousTwoMinersMissedTheirTimeSlot = myOrder > 2 &&
                                                       round.RealTimeMinersInformation.Values
                                                       .First(m => m.Order == myOrder - 1).OutValue == null &&
                                                       round.RealTimeMinersInformation.Values
                                                       .First(m => m.Order == myOrder - 2).OutValue == null;
            var skipTimeSlot = previousMinerMissedHisTimeSlot && !previousTwoMinersMissedTheirTimeSlot &&
                               isTimeSlotSkippable;

            var firstMinerOfCurrentRound =
                round.RealTimeMinersInformation.Values.FirstOrDefault(m => m.OutValue != null);

            switch (behaviour)
            {
            case DPoSBehaviour.UpdateValueWithoutPreviousInValue:
                // Two reasons of `UpdateValueWithoutPreviousInValue` behaviour:
                // 1. 1st round of 1st term.
                // 2. Term changed in current round.
                if (skipTimeSlot)
                {
                    if (firstMinerOfCurrentRound != null)
                    {
                        var roundStartTimeInTheory = firstMinerOfCurrentRound.ActualMiningTime.ToDateTime()
                                                     .AddMilliseconds(-firstMinerOfCurrentRound.Order * miningInterval);
                        var minersCount = round.RealTimeMinersInformation.Count;
                        var extraBlockMiningTimeInTheory =
                            roundStartTimeInTheory.AddMilliseconds(minersCount * miningInterval);
                        nextBlockMiningLeftMilliseconds =
                            (int)(round.ArrangeAbnormalMiningTime(publicKey, extraBlockMiningTimeInTheory,
                                                                  miningInterval).ToDateTime() - dateTime).TotalMilliseconds;
                        // If someone produced block in current round before.

                        hint = new DPoSHint
                        {
                            Behaviour = DPoSBehaviour.NextRound
                        }.ToByteString();
                        break;
                    }

                    nextBlockMiningLeftMilliseconds = minerInRound.Order * miningInterval * 2 + miningInterval;
                    hint = new DPoSHint
                    {
                        Behaviour = DPoSBehaviour.NextRound
                    }.ToByteString();
                    break;
                }

                nextBlockMiningLeftMilliseconds = minerInRound.Order * miningInterval;
                break;

            case DPoSBehaviour.UpdateValue:
                // If miner of previous order didn't produce block, skip this time slot.
                if (skipTimeSlot)
                {
                    nextBlockMiningLeftMilliseconds = (int)(round.ArrangeAbnormalMiningTime(minerInRound.PublicKey,
                                                                                            round.GetExtraBlockMiningTime(),
                                                                                            round.GetMiningInterval()).ToDateTime() - dateTime)
                                                      .TotalMilliseconds;
                    hint = new DPoSHint
                    {
                        Behaviour = DPoSBehaviour.NextRound
                    }.ToByteString();
                    break;
                }

                nextBlockMiningLeftMilliseconds =
                    (int)(expectedMiningTime.ToDateTime() - dateTime).TotalMilliseconds;
                break;

            case DPoSBehaviour.NextRound:
                nextBlockMiningLeftMilliseconds = round.RoundNumber == 1
                        ? round.RealTimeMinersInformation.Count * miningInterval + myOrder * miningInterval
                        : (int)(round.ArrangeAbnormalMiningTime(minerInRound.PublicKey, dateTime).ToDateTime() -
                                dateTime).TotalMilliseconds;
                break;

            case DPoSBehaviour.NextTerm:
                nextBlockMiningLeftMilliseconds =
                    (int)(round.ArrangeAbnormalMiningTime(minerInRound.PublicKey, dateTime).ToDateTime() -
                          dateTime).TotalMilliseconds;
                break;

            default:
                return(new ConsensusCommand
                {
                    ExpectedMiningTime = expectedMiningTime,
                    NextBlockMiningLeftMilliseconds = int.MaxValue,
                    LimitMillisecondsOfMiningBlock = int.MaxValue,
                    Hint = new DPoSHint
                    {
                        Behaviour = DPoSBehaviour.Nothing
                    }.ToByteString()
                });
            }

            return(new ConsensusCommand
            {
                ExpectedMiningTime = expectedMiningTime,
                NextBlockMiningLeftMilliseconds = nextBlockMiningLeftMilliseconds,
                LimitMillisecondsOfMiningBlock = miningInterval / minerInRound.PromisedTinyBlocks,
                Hint = hint
            });
        }