示例#1
0
        /// <summary>
        /// Returns the difficulty target as a 256 bit value that can be compared to a SHA-256 hash. Inside a block the
        /// target is represented using a compact form. If this form decodes to a value that is out of bounds,
        /// an exception is thrown.
        /// </summary>
        /// <exception cref="BitCoinSharp.VerificationException" />
        public BigInteger GetDifficultyTargetAsInteger()
        {
            var target = Utils.DecodeCompactBits(_difficultyTarget);

            if (target.CompareTo(BigInteger.Zero) <= 0 || target.CompareTo(Params.ProofOfWorkLimit) > 0)
            {
                throw new VerificationException("Difficulty target is bad: " + target);
            }
            return(target);
        }
示例#2
0
        /// <summary>
        /// Throws an exception if the blocks difficulty is not correct.
        /// </summary>
        /// <exception cref="BitCoinSharp.BlockStoreException" />
        /// <exception cref="BitCoinSharp.VerificationException" />
        private void CheckDifficultyTransitions(StoredBlock storedPrev, StoredBlock storedNext)
        {
            var prev = storedPrev.Header;
            var next = storedNext.Header;

            // Is this supposed to be a difficulty transition point?
            if ((storedPrev.Height + 1) % _params.Interval != 0)
            {
                // No ... so check the difficulty didn't actually change.
                if (next.DifficultyTarget != prev.DifficultyTarget)
                {
                    throw new VerificationException("Unexpected change in difficulty at height " + storedPrev.Height +
                                                    ": " + next.DifficultyTarget.ToString("x") + " vs " +
                                                    prev.DifficultyTarget.ToString("x"));
                }
                return;
            }

            // We need to find a block far back in the chain. It's OK that this is expensive because it only occurs every
            // two weeks after the initial block chain download.
            var now    = Environment.TickCount;
            var cursor = _blockStore.Get(prev.Hash);

            for (var i = 0; i < _params.Interval - 1; i++)
            {
                if (cursor == null)
                {
                    // This should never happen. If it does, it means we are following an incorrect or busted chain.
                    throw new VerificationException(
                              "Difficulty transition point but we did not find a way back to the genesis block.");
                }
                cursor = _blockStore.Get(cursor.Header.PrevBlockHash);
            }
            _log.InfoFormat("Difficulty transition traversal took {0}ms", Environment.TickCount - now);

            var blockIntervalAgo = cursor.Header;
            var timespan         = (int)(prev.Time - blockIntervalAgo.Time);

            // Limit the adjustment step.
            if (timespan < _params.TargetTimespan / 4)
            {
                timespan = _params.TargetTimespan / 4;
            }
            if (timespan > _params.TargetTimespan * 4)
            {
                timespan = _params.TargetTimespan * 4;
            }

            var newDifficulty = Utils.DecodeCompactBits(blockIntervalAgo.DifficultyTarget);

            newDifficulty = newDifficulty.Multiply(BigInteger.ValueOf(timespan));
            newDifficulty = newDifficulty.Divide(BigInteger.ValueOf(_params.TargetTimespan));

            if (newDifficulty.CompareTo(_params.ProofOfWorkLimit) > 0)
            {
                _log.WarnFormat("Difficulty hit proof of work limit: {0}", newDifficulty.ToString(16));
                newDifficulty = _params.ProofOfWorkLimit;
            }

            var accuracyBytes      = (int)(next.DifficultyTarget >> 24) - 3;
            var receivedDifficulty = next.GetDifficultyTargetAsInteger();

            // The calculated difficulty is to a higher precision than received, so reduce here.
            var mask = BigInteger.ValueOf(0xFFFFFF).ShiftLeft(accuracyBytes * 8);

            newDifficulty = newDifficulty.And(mask);

            if (newDifficulty.CompareTo(receivedDifficulty) != 0)
            {
                throw new VerificationException("Network provided difficulty bits do not match what was calculated: " +
                                                receivedDifficulty.ToString(16) + " vs " + newDifficulty.ToString(16));
            }
        }