Exemple #1
0
        /// <summary>
        /// Calculates the difficulty for the next block given a previous blocks header, the timestamp of the new block, and the configuration.
        /// </summary>
        /// <param name="parentBlockHeader">The previous block header from which we derive difficulty.</param>
        /// <param name="timestamp">The timestamp of the new block.</param>
        /// <param name="configuration">The configuration under which we calculate difficulty.</param>
        /// <returns>Returns the difficulty for the supposed new block.</returns>
        public static BigInteger CalculateDifficulty(BlockHeader parentBlockHeader, BigInteger timestamp, Configuration.Configuration configuration)
        {
            // Handle the special case of difficulty for test chains (difficulty 1 keeps difficulty at 1).
            if (parentBlockHeader.Difficulty == 1)
            {
                return(1);
            }

            // Check our versioning
            BigInteger newBlockNumber = parentBlockHeader.BlockNumber + 1;
            bool       isByzantium    = newBlockNumber >= configuration.GetReleaseStartBlockNumber(Configuration.EthereumRelease.Byzantium);
            bool       isHomestead    = newBlockNumber >= configuration.GetReleaseStartBlockNumber(Configuration.EthereumRelease.Homestead);

            // TODO: Revisit the rest of this. Currently a poor implementation. Use following as source: https://dltlabs.com/how-difficulty-adjustment-algorithm-works-in-ethereum/
            BigInteger offset    = parentBlockHeader.Difficulty / configuration.DifficultyFactor;
            BigInteger sign      = 0;
            BigInteger deltaTime = timestamp - parentBlockHeader.Timestamp;

            if (isByzantium)
            {
                BigInteger x = 2;
                if (parentBlockHeader.UnclesHash.ValuesEqual(BLANK_UNCLES_HASH))
                {
                    x = 1;
                }

                sign = BigInteger.Max(-99, x - (deltaTime / configuration.DifficultyAdjustmentCutOffByzantium));
            }
            else if (isHomestead)
            {
                sign = BigInteger.Max(-99, 1 - (deltaTime / configuration.DifficultyAdjustmentCutOffHomestead));
            }
            else
            {
                if (deltaTime < configuration.DifficultyAdjustmentCutOff)
                {
                    sign = 1;
                }
                else
                {
                    sign = -1;
                }
            }

            BigInteger minDifficulty = BigInteger.Min(configuration.MinDifficulty, parentBlockHeader.Difficulty);
            BigInteger difficulty    = BigInteger.Max(minDifficulty, parentBlockHeader.Difficulty + (offset * sign));
            BigInteger periods       = newBlockNumber / configuration.DifficultyExponentialPeriod;

            if (isByzantium)
            {
                periods -= configuration.DifficultyExponentialFreePeriodsByzantium;
            }

            if (periods >= configuration.DifficultyExponentialFreePeriods)
            {
                BigInteger exponent = periods - configuration.DifficultyExponentialFreePeriods;
                return(BigInteger.Max(difficulty + BigInteger.Pow(2, (int)exponent), configuration.MinDifficulty));
            }

            return(difficulty);
        }