/// <summary>
        /// AElf Consensus Behaviour is changeable in this method when
        /// this miner should skip his time slot more precisely.
        /// </summary>
        /// <param name="behaviour"></param>
        /// <param name="currentRound"></param>
        /// <param name="pubkey"></param>
        /// <param name="currentBlockTime"></param>
        /// <returns></returns>
        private ConsensusCommand GetConsensusCommand(AElfConsensusBehaviour behaviour, Round currentRound,
                                                     string pubkey, Timestamp currentBlockTime = null)
        {
            if (SolitaryMinerDetection(currentRound, pubkey))
            {
                return(ConsensusCommandProvider.InvalidConsensusCommand);
            }

            if (currentRound.RoundNumber == 1 && behaviour != AElfConsensusBehaviour.TinyBlock)
            {
                return(new ConsensusCommandProvider(new FirstRoundCommandStrategy(currentRound, pubkey,
                                                                                  currentBlockTime, behaviour)).GetConsensusCommand());
            }

            Context.LogDebug(() => $"Params to get command: {behaviour}, {pubkey}, {currentBlockTime}");
            switch (behaviour)
            {
            case AElfConsensusBehaviour.UpdateValue:
                TryToGetPreviousRoundInformation(out var previousRound);
                return(new ConsensusCommandProvider(new NormalBlockCommandStrategy(currentRound, pubkey,
                                                                                   currentBlockTime, previousRound.RoundId)).GetConsensusCommand());

            case AElfConsensusBehaviour.NextRound:
            case AElfConsensusBehaviour.NextTerm:
                return(new ConsensusCommandProvider(
                           new TerminateRoundCommandStrategy(currentRound, pubkey, currentBlockTime,
                                                             behaviour == AElfConsensusBehaviour.NextTerm))
                       .GetConsensusCommand());

            case AElfConsensusBehaviour.TinyBlock:
            {
                var consensusCommand =
                    new ConsensusCommandProvider(new TinyBlockCommandStrategy(currentRound, pubkey,
                                                                              currentBlockTime, GetMaximumBlocksCount())).GetConsensusCommand();
                if (consensusCommand.Hint ==
                    new AElfConsensusHint {
                        Behaviour = AElfConsensusBehaviour.NextRound
                    }.ToByteString())
                {
                    Context.LogDebug(() => "Re-arranged behaviour from TinyBlock to NextRound.");
                }

                return(consensusCommand);
            }

            default:
                return(ConsensusCommandProvider.InvalidConsensusCommand);
            }
        }
예제 #2
0
        /// <summary>
        /// AElf Consensus Behaviour is changeable in this method when
        /// this miner should skip his time slot more precisely.
        /// </summary>
        /// <param name="behaviour"></param>
        /// <param name="currentRound"></param>
        /// <param name="publicKey"></param>
        /// <returns></returns>
        private ConsensusCommand GetConsensusCommand(AElfConsensusBehaviour behaviour, Round currentRound,
                                                     string publicKey)
        {
            if (SolitaryMinerDetection(currentRound, publicKey))
            {
                return(ConsensusCommandProvider.InvalidConsensusCommand);
            }

            var currentBlockTime = Context.CurrentBlockTime;

            if (currentRound.RoundNumber == 1 && behaviour != AElfConsensusBehaviour.TinyBlock)
            {
                return(new ConsensusCommandProvider(new FirstRoundCommandStrategy(currentRound, publicKey,
                                                                                  currentBlockTime, behaviour)).GetConsensusCommand());
            }

            switch (behaviour)
            {
            case AElfConsensusBehaviour.UpdateValueWithoutPreviousInValue:
            case AElfConsensusBehaviour.UpdateValue:
                return(new ConsensusCommandProvider(new NormalBlockCommandStrategy(currentRound, publicKey,
                                                                                   currentBlockTime)).GetConsensusCommand());

            case AElfConsensusBehaviour.NextRound:
            case AElfConsensusBehaviour.NextTerm:
                return(new ConsensusCommandProvider(
                           new TerminateRoundCommandStrategy(currentRound, publicKey, currentBlockTime,
                                                             behaviour == AElfConsensusBehaviour.NextTerm))
                       .GetConsensusCommand());

            case AElfConsensusBehaviour.TinyBlock:
            {
                var consensusCommand =
                    new ConsensusCommandProvider(new TinyBlockCommandStrategy(currentRound, publicKey,
                                                                              currentBlockTime, GetMaximumBlocksCount())).GetConsensusCommand();
                if (consensusCommand.Hint ==
                    new AElfConsensusHint {
                        Behaviour = AElfConsensusBehaviour.NextRound
                    }.ToByteString())
                {
                    Context.LogDebug(() => "Re-arranged behaviour from TinyBlock to NextRound.");
                }

                return(consensusCommand);
            }
            }

            return(ConsensusCommandProvider.InvalidConsensusCommand);
        }
예제 #3
0
 public FirstRoundCommandStrategy(Round currentRound, string pubkey, Timestamp currentBlockTime,
                                  AElfConsensusBehaviour consensusBehaviour) : base(currentRound, pubkey, currentBlockTime)
 {
     _consensusBehaviour = consensusBehaviour;
 }
        /// <summary>
        /// AElf Consensus 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="currentRound"></param>
        /// <param name="publicKey"></param>
        /// <returns></returns>
        private ConsensusCommand GetConsensusCommand(AElfConsensusBehaviour behaviour, Round currentRound,
                                                     string publicKey)
        {
            var miningInterval = currentRound.GetMiningInterval();

            while (true)
            {
                var isAlone = CheckLonelyMiner(publicKey);
                if (behaviour == AElfConsensusBehaviour.TinyBlock && isAlone &&
                    currentRound.RealTimeMinersInformation.Count >
                    2 // There are more than 1 miner possible to save him.
                    )
                {
                    behaviour = AElfConsensusBehaviour.Nothing;
                }

                var       currentBlockTime = Context.CurrentBlockTime;
                Timestamp expectedMiningTime;
                int       nextBlockMiningLeftMilliseconds;

                switch (behaviour)
                {
                case AElfConsensusBehaviour.UpdateValueWithoutPreviousInValue:
                    GetScheduleForUpdateValueWithoutPreviousInValue(currentRound, publicKey,
                                                                    out nextBlockMiningLeftMilliseconds, out expectedMiningTime);
                    break;

                case AElfConsensusBehaviour.UpdateValue:
                    expectedMiningTime = currentRound.GetExpectedMiningTime(publicKey);
                    nextBlockMiningLeftMilliseconds = (int)(expectedMiningTime - currentBlockTime).Milliseconds();
                    break;

                case AElfConsensusBehaviour.TinyBlock:
                    GetScheduleForTinyBlock(currentRound, publicKey,
                                            out nextBlockMiningLeftMilliseconds, out expectedMiningTime);
                    if (nextBlockMiningLeftMilliseconds < 0)
                    {
                        Context.LogDebug(() =>
                                         "Next block mining left milliseconds is less than 0 for tiny block.");
                        behaviour = AElfConsensusBehaviour.NextRound;
                        continue;
                    }

                    break;

                case AElfConsensusBehaviour.NextRound:
                    GetScheduleForNextRound(currentRound, publicKey,
                                            out nextBlockMiningLeftMilliseconds, out expectedMiningTime);
                    break;

                case AElfConsensusBehaviour.NextTerm:
                    expectedMiningTime = currentRound.ArrangeAbnormalMiningTime(publicKey, currentBlockTime);
                    if (currentRound.RealTimeMinersInformation.Single(m => m.Value.IsExtraBlockProducer).Key !=
                        publicKey)
                    {
                        expectedMiningTime.AddMilliseconds(miningInterval);
                    }

                    nextBlockMiningLeftMilliseconds = (int)(expectedMiningTime - currentBlockTime).Milliseconds();
                    break;

                case AElfConsensusBehaviour.Nothing:
                    return(GetInvalidConsensusCommand());

                default:
                    return(GetInvalidConsensusCommand());
                }

                AdjustLimitMillisecondsOfMiningBlock(currentRound, publicKey, nextBlockMiningLeftMilliseconds,
                                                     out var limitMillisecondsOfMiningBlock);

                var milliseconds = nextBlockMiningLeftMilliseconds;
                Context.LogDebug(() => $"NextBlockMiningLeftMilliseconds: {milliseconds}");

                // Produce tiny blocks as fast as one can.
                if (behaviour == AElfConsensusBehaviour.TinyBlock)
                {
                    nextBlockMiningLeftMilliseconds = AEDPoSContractConstants.MinimumIntervalOfProducingBlocks;
                }

                return(new ConsensusCommand
                {
                    ExpectedMiningTime = expectedMiningTime,
                    NextBlockMiningLeftMilliseconds =
                        nextBlockMiningLeftMilliseconds < 0 ? 0 : nextBlockMiningLeftMilliseconds,
                    LimitMillisecondsOfMiningBlock = isAlone
                        ? currentRound.GetMiningInterval()
                        : behaviour == AElfConsensusBehaviour.NextTerm
                            ? miningInterval
                            : limitMillisecondsOfMiningBlock,
                    Hint = new AElfConsensusHint {
                        Behaviour = behaviour
                    }.ToByteString()
                });
            }
        }