/// <summary> /// Checks that the nBits field of a block follow protocol rules. /// </summary> internal static bool IsNBitsValid(StoredBlock block, Subchain parentChain) { //todo: add test for this method StoredBlock parentBlock = parentChain.GetBlockByOffset(0); BigInteger blockDifficultyTarget = DifficultyUtils.NBitsToTarget(block.Header.NBits); if (block.Height%DifficultyUtils.DifficultyAdjustmentIntervalInBlocks != 0) { BigInteger parentBlockDifficultyTarget = DifficultyUtils.NBitsToTarget(parentBlock.Header.NBits); if (blockDifficultyTarget != parentBlockDifficultyTarget) { return false; } } else { StoredBlock baseBlock = parentChain.GetBlockByHeight(block.Height - DifficultyUtils.DifficultyAdjustmentIntervalInBlocks); // todo: check against non-bugged value and allow some percent-based difference? // Note: There is a known bug here. It known as "off-by-one" or "Time Warp Bug". // Bug Description: http://bitcoin.stackexchange.com/questions/20597/where-exactly-is-the-off-by-one-difficulty-bug // Related Attack Description: https://bitcointalk.org/index.php?topic=43692.msg521772#msg521772 uint timeSpent = parentBlock.Header.Timestamp - baseBlock.Header.Timestamp; BigInteger oldTarget = DifficultyUtils.NBitsToTarget(parentBlock.Header.NBits); var newTarget = DifficultyUtils.CalculateNewTarget(timeSpent, oldTarget); // this rounds newTarget value to a value that would fit into NBits uint newNBits = DifficultyUtils.TargetToNBits(newTarget); newTarget = DifficultyUtils.NBitsToTarget(newNBits); if (blockDifficultyTarget != newTarget) { return false; } } return true; }
/// <summary> /// Checks that timestamp of the block is after median time of the last 11 blocks. /// </summary> internal static bool IsTimeStampValid(StoredBlock block, Subchain parentChain) { //todo: use network settings const int medianBlockCount = 11; List<uint> oldTimestamps = new List<uint>(medianBlockCount); for (int i = 0; i < medianBlockCount && i < parentChain.Length; i++) { oldTimestamps.Add(parentChain.GetBlockByOffset(i).Header.Timestamp); } oldTimestamps.Sort(); uint medianTimestamp = oldTimestamps[oldTimestamps.Count/2]; return block.Header.Timestamp > medianTimestamp; }