예제 #1
0
        public uint GetNextWorkRequired(HeaderNode previousHeaderNode, BlockHeader header)
        {
            if (previousHeaderNode == null)
            {
                ThrowHelper.ThrowArgumentNullException(nameof(previousHeaderNode));
            }

            if (!_blockHeaderRepository.TryGet(previousHeaderNode.Hash, out BlockHeader? previousHeader))
            {
                //this should never happens, if it happens means we have consistency problem (we lost an header)
                ThrowHelper.ThrowArgumentNullException(nameof(previousHeaderNode));
            }

            uint proofOfWorkLimit             = _consensusParameters.PowLimit.ToCompact();
            int  difficultyAdjustmentInterval = (int)GetDifficultyAdjustmentInterval();

            // Only change once per difficulty adjustment interval
            if ((previousHeaderNode.Height + 1) % difficultyAdjustmentInterval != 0)
            {
                if (_consensusParameters.PowAllowMinDifficultyBlocks)
                {
                    /// Special difficulty rule for test networks:
                    /// if the new block's timestamp is more than 2 times the PoWTargetSpacing then allow mining of a min-difficulty block.
                    if (header.TimeStamp > (previousHeader.TimeStamp + (_consensusParameters.PowTargetSpacing * 2)))
                    {
                        return(proofOfWorkLimit);
                    }
                    else
                    {
                        // Return the last non-special-min-difficulty-rules-block.
                        HeaderNode  currentHeaderNode = previousHeaderNode;
                        BlockHeader currentHeader     = previousHeader;
                        while (currentHeaderNode.Previous != null &&
                               (currentHeaderNode.Height % difficultyAdjustmentInterval) != 0 &&
                               _blockHeaderRepository.TryGet(currentHeaderNode.Hash, out currentHeader !) && currentHeader.Bits == proofOfWorkLimit
                               )
                        {
                            currentHeaderNode = currentHeaderNode.Previous;
                        }

                        return(currentHeader.Bits);
                    }
                }

                return(previousHeader.Bits);
            }

            // Go back by what we want to be 14 days worth of blocks
            int        heightReference     = previousHeaderNode.Height - (difficultyAdjustmentInterval - 1);
            HeaderNode?headerNodeReference = previousHeaderNode.GetAncestor(heightReference);

            BlockHeader?headerReference = null;

            if (headerNodeReference == null || !_blockHeaderRepository.TryGet(headerNodeReference.Hash, out headerReference))
            {
                ThrowHelper.ThrowNotSupportedException("Header ancestor not found, PoW required work computation requires a full chain.");
            }

            return(CalculateNextWorkRequired(previousHeader, headerReference.TimeStamp));
        }
예제 #2
0
        public BlockHeader GetTipHeader()
        {
            using Microsoft.VisualStudio.Threading.AsyncReaderWriterLock.Releaser readMainLock = GlobalLocks.ReadOnMainAsync().GetAwaiter().GetResult();
            if (!_blockHeaderRepository.TryGet(ChainTip.Hash, out BlockHeader? header))
            {
                ThrowHelper.ThrowBlockHeaderRepositoryException($"Unexpected error, cannot fetch the tip at height {ChainTip.Height}.");
            }

            return(header !);
        }
        /// <summary>
        /// Calculate (backward) the median block time over <see cref="MEDIAN_TIMESPAN" /> window from this entry in the chain.
        /// </summary>
        /// <param name="startingBlockHash">The starting block hash.</param>
        /// <param name="startingBlockHeight">Height of the starting block.</param>
        /// <returns>
        /// The median block time.
        /// </returns>
        public uint Calculate(UInt256 startingBlockHash, int startingBlockHeight)
        {
            if (startingBlockHeight < 0)
            {
                ThrowHelper.ThrowArgumentException("{startingBlockHeight} must be greater or equal than 0");
            }

            int samplesLenght = startingBlockHeight > MEDIAN_TIMESPAN ? MEDIAN_TIMESPAN : startingBlockHeight + 1;

            uint[]? median = new uint[samplesLenght];

            if (!_blockHeaderRepository.TryGet(startingBlockHash, out BlockHeader? currentHeader))
            {
                ThrowHelper.ThrowNotSupportedException("Fatal exception, shouldn't happen, repository may be corrupted.");
            }

            for (int i = samplesLenght - 1; i > 0; i--)
            {
                median[i] = currentHeader.TimeStamp;

                if (!_blockHeaderRepository.TryGet(currentHeader.PreviousBlockHash !, out currentHeader))
                {
                    ThrowHelper.ThrowNotSupportedException("Fatal exception, shouldn't happen, repository may be corrupted.");
                }
            }

            median[0] = currentHeader.TimeStamp;

            Array.Sort(median);
            return(median[samplesLenght / 2]);
        }