public virtual Block CreateValidBlockAndAddToChain(string privateKey, Blockchain blockchain, uint protocolVersion, IEnumerable <AbstractTransaction> transactions, BigDecimal difficulty, BigDecimal maximumTarget, CancellationToken ct) { if (difficulty < 1) { throw new DifficultyCalculationException("Difficulty cannot be zero."); } bool targetMet = false; var currentTarget = maximumTarget / difficulty; Block b = PrepareBlock(blockchain, protocolVersion, transactions, currentTarget); // Keep on mining while (targetMet == false) { ct.ThrowIfCancellationRequested(); if (hotRestart) { b = PrepareBlock(blockchain, protocolVersion, transactions, currentTarget); hotRestart = false; } if (b.Header.Nonce == ulong.MaxValue) { throw new NonceLimitReachedException(); } b.Header.IncrementNonce(); var hash = _blockFinalizer.CalculateHash(b); _blockFinalizer.FinalizeBlock(b, hash, privateKey); try { _validator.ValidateBlock(b, currentTarget, blockchain, true, true); targetMet = true; } catch (BlockRejectedException ex) { if (ex.Message != "Hash has no leading zero" && ex.Message != "Hash value is equal or higher than the current target") { throw; } } } return(b); }
public virtual void ValidateBlockHeader(Block block, BigDecimal hashValue, BigDecimal currentTarget, bool checkTimestamp, string netId) { // The block must be in the same network as our node if (block.Header.MagicNumber != netId) { throw new BlockRejectedException("Block comes from a different network", block); } if (!block.Header.IsFinalized()) { throw new BlockRejectedException("Block is not hashed or signed or hashed properly", block); } else if (block.Header.Hash != _blockFinalizer.CalculateHash(block)) { throw new BlockRejectedException("The hash property of the block is not equal to the calculated hash", block); } // Hash value must be lower than the target and the first byte must be zero // because the first byte indidates if the hashValue is a positive or negative number, // negative numbers are not allowed. if (!block.Header.Hash.StartsWith("0")) { throw new BlockRejectedException("Hash has no leading zero", block); } // The hash value must be lower than the given target if (hashValue >= currentTarget) { throw new BlockRejectedException("Hash value is equal or higher than the current target", block); } if (!checkTimestamp) { return; } // Timestamp must not be lower than UTC - 2 min and not higher than UTC + 2 min if (_timestamper.GetCurrentUtcTimestamp() - block.Header.Timestamp > BlockchainConstants.MaximumTimestampOffset || _timestamper.GetCurrentUtcTimestamp() - block.Header.Timestamp < (BlockchainConstants.MaximumTimestampOffset * -1)) { throw new BlockRejectedException("Block timestamp differs too much"); } }