Beispiel #1
0
        protected virtual (Share Share, string BlockHex) ProcessShareInternal(StratumClient worker, string nonce,
                                                                              uint nTime, string solution)
        {
            var context       = worker.ContextAs <BitcoinWorkerContext>();
            var solutionBytes = solution.HexToByteArray();

            // serialize block-header
            var headerBytes = SerializeHeader(nTime, nonce); // 144 bytes (doesn't contain soln)

            // verify solution
            if (!equihash.Verify(headerBytes, solutionBytes.Skip(chainConfig.SolutionPreambleSize).ToArray())) // skip preamble (3 bytes)
            {
                throw new StratumException(StratumError.Other, "invalid solution");
            }

            // hash block-header
            var         headerSolutionBytes = headerBytes.Concat(solutionBytes).ToArray();
            Span <byte> headerHash          = stackalloc byte[32];

            headerHasher.Digest(headerSolutionBytes, headerHash, (ulong)nTime);
            var headerValue = new uint256(headerHash);

            // calc share-diff
            var shareDiff         = (double)new BigRational(chainConfig.Diff1b, headerHash.ToBigInteger()) * shareMultiplier;
            var stratumDifficulty = context.Difficulty;
            var ratio             = shareDiff / stratumDifficulty;

            // check if the share meets the much harder block difficulty (block candidate)
            var isBlockCandidate = headerValue <= blockTargetValue;

            // test if share meets at least workers current difficulty
            if (!isBlockCandidate && ratio < 0.99)
            {
                // check if share matched the previous difficulty from before a vardiff retarget
                if (context.VarDiff?.LastUpdate != null && context.PreviousDifficulty.HasValue)
                {
                    ratio = shareDiff / context.PreviousDifficulty.Value;

                    if (ratio < 0.99)
                    {
                        throw new StratumException(StratumError.LowDifficultyShare, $"low difficulty share ({shareDiff})");
                    }

                    // use previous difficulty
                    stratumDifficulty = context.PreviousDifficulty.Value;
                }

                else
                {
                    throw new StratumException(StratumError.LowDifficultyShare, $"low difficulty share ({shareDiff})");
                }
            }

            var result = new Share
            {
                BlockHeight       = BlockTemplate.Height,
                NetworkDifficulty = Difficulty,
                Difficulty        = stratumDifficulty,
            };

            if (isBlockCandidate)
            {
                var headerHashReversed = headerHash.ToNewReverseArray();

                result.IsBlockCandidate = true;
                result.BlockReward      = rewardToPool.ToDecimal(MoneyUnit.BTC);
                result.BlockHash        = headerHashReversed.ToHexString();

                var blockBytes = SerializeBlock(headerBytes, coinbaseInitial, solutionBytes);
                var blockHex   = blockBytes.ToHexString();

                return(result, blockHex);
            }

            return(result, null);
        }
Beispiel #2
0
        protected virtual (Share Share, string BlockHex) ProcessShareInternal(StratumClient worker, string extraNonce,
                                                                              uint nTime, string nonce, string solution)
        {
            var context         = worker.ContextAs <BitcoinWorkerContext>();
            var solutionBytes   = solution.HexToByteArray();
            var extraNonceBytes = extraNonce.HexToByteArray();
            var nonceInt        = uint.Parse(nonce, NumberStyles.HexNumber);

            // serialize block-header
            var headerBytes = SerializeHeader(nTime, extraNonceBytes, nonceInt);

            // verify solution
            if (!equihash.Verify(headerBytes, solutionBytes))
            {
                throw new StratumException(StratumError.Other, "invalid solution");
            }

            // hash block-header
            var headerSolutionBytes = headerBytes.Concat(solutionBytes).ToArray();
            var headerHash          = headerHasher.Digest(headerSolutionBytes);
            var headerValue         = new uint256(headerHash);

            // calc share-diff
            double shareDiff         = (double)new BigRational(chainConfig.Diff1b, headerHash.ToBigInteger());
            var    stratumDifficulty = context.Difficulty;
            var    ratio             = shareDiff / stratumDifficulty;

            // check if the share meets the much harder block difficulty (block candidate)
            var isBlockCandidate = headerValue < blockTarget.ToUInt256();

            // test if share meets at least workers current difficulty
            if (!isBlockCandidate && ratio < 0.99)
            {
                // check if share matched the previous difficulty from before a vardiff retarget
                if (context.VarDiff?.LastUpdate != null && context.PreviousDifficulty.HasValue)
                {
                    ratio = shareDiff / context.PreviousDifficulty.Value;

                    if (ratio < 0.99)
                    {
                        throw new StratumException(StratumError.LowDifficultyShare, $"low difficulty share ({shareDiff})");
                    }

                    // use previous difficulty
                    stratumDifficulty = context.PreviousDifficulty.Value;
                }

                else
                {
                    throw new StratumException(StratumError.LowDifficultyShare, $"low difficulty share ({shareDiff})");
                }
            }

            var result = new Share
            {
                BlockHeight       = BlockHeader.Height,
                NetworkDifficulty = Difficulty,
                Difficulty        = stratumDifficulty,
            };

            if (isBlockCandidate)
            {
                result.IsBlockCandidate = true;
                result.BlockHash        = headerValue.ToString();

                var blockHex = headerSolutionBytes.ToHexString();

                return(result, blockHex);
            }

            return(result, null);
        }