BitSharper.BlockChain.CheckDifficultyTransitions C# (CSharp) Method

CheckDifficultyTransitions() private method

Throws an exception if the blocks difficulty is not correct.
private CheckDifficultyTransitions ( StoredBlock storedPrev, StoredBlock storedNext ) : void
storedPrev StoredBlock
storedNext StoredBlock
return void
        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.DebugFormat("Difficulty transition traversal took {0}ms", Environment.TickCount - now);

            var blockIntervalAgo = cursor.Header;
            var timespan = (int) (prev.TimeSeconds - blockIntervalAgo.TimeSeconds);
            // 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.DebugFormat("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));
        }