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);
        }
Example #2
0
        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");
            }
        }