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

                        var headerBytes = SerializeHeader(nTime, nonce); 
                        if (!equihash.Verify(headerBytes, solutionBytes.Skip(3).ToArray()))                 throw new StratumException(StratumError.Other, "invalid solution");

                        var headerSolutionBytes = headerBytes.Concat(solutionBytes).ToArray();
            var headerHash = headerHasher.Digest(headerSolutionBytes, (ulong) nTime);
            var headerHashReversed = headerHash.ToReverseArray();
            var headerValue = new uint256(headerHash);

                        var shareDiff = (double) new BigRational(coinbaseTxConfig.Diff1b, headerHash.ToBigInteger()) * shareMultiplier;
            var stratumDifficulty = context.Difficulty;
            var ratio = shareDiff / stratumDifficulty;

                        var isBlockCandidate = headerValue <= blockTargetValue;

                        if (!isBlockCandidate && ratio < 0.99)
            {
                                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})");

                                        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)
            {
                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);
        }
Example #2
0
        protected virtual BitcoinShare ProcessShareInternal(StratumClient <BitcoinWorkerContext> worker, string nonce,
                                                            uint nTime, string solution)
        {
            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(3).ToArray())) // skip preamble (3 bytes)
            {
                throw new StratumException(StratumError.Other, "invalid solution");
            }

            // hash block-header
            var headerSolutionBytes = headerBytes.Concat(solutionBytes).ToArray();
            var headerHash          = headerHasher.Digest(headerSolutionBytes, (ulong)nTime);
            var headerValue         = BigInteger.Parse("00" + headerHash.ReverseArray().ToHexString(), NumberStyles.HexNumber);

            // calc share-diff
            var shareDiff         = (double)new BigRational(ZCashConstants.Diff1b, headerValue) * shareMultiplier;
            var stratumDifficulty = worker.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 (worker.Context.VarDiff?.LastUpdate != null && worker.Context.PreviousDifficulty.HasValue)
                {
                    ratio = shareDiff / worker.Context.PreviousDifficulty.Value;

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

                    // use previous difficulty
                    stratumDifficulty = worker.Context.PreviousDifficulty.Value;
                }

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

            var result = new BitcoinShare
            {
                BlockHeight      = BlockTemplate.Height,
                IsBlockCandidate = isBlockCandidate
            };

            var blockBytes = SerializeBlock(headerBytes, coinbaseInitial, solutionBytes);

            result.BlockHex    = blockBytes.ToHexString();
            result.BlockHash   = headerHash.ToHexString();
            result.BlockHeight = BlockTemplate.Height;
            result.BlockReward = rewardToPool.ToDecimal(MoneyUnit.BTC);
            result.Difficulty  = stratumDifficulty;

            return(result);
        }
Example #3
0
        protected virtual (Share Share, string BlockHex) ProcessShareInternal(StratumClient worker, string nonce, uint nTime, string solution)
        {
            var context       = worker.ContextAs <BitcoinWorkerContext>();
            var solutionBytes = (Span <byte>)solution.HexToByteArray();

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

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

            // concat header and solution
            Span <byte> headerSolutionBytes = stackalloc byte[headerBytes.Length + solutionBytes.Length];

            headerBytes.CopyTo(headerSolutionBytes);
            solutionBytes.CopyTo(headerSolutionBytes.Slice(headerBytes.Length));

            // hash block-header
            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(networkParams.Diff1BValue, 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 <= 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);
        }
Example #4
0
        private (Share Share, string nonce, string solution, string headerHash, string nTime) ProcessShareInternal(
            StratumClient worker, string nonce, string nTime, string solution)
        {
            var context       = worker.ContextAs <AionWorkerContext>();
            var solutionBytes = solution.HexToByteArray();
            // serialize block-header
            var headerBytes = SerializeHeader(nonce);

            // verify solution
            if (!equihash.Verify(headerBytes, solutionBytes))
            {
                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);
            var headerHashReversed = headerHash.ToNewReverseArray();
            var headerValue        = headerHashReversed.ToBigInteger();
            var target             = new BigInteger(blockTarget.ToBytes());

            var isBlockCandidate = target > headerValue;

            logger.Debug(() => $"context.Difficulty:{context.Difficulty} Difficulty: {Difficulty}");
            // calc share-diff
            var stratumDifficulty = context.Difficulty > Difficulty ? Difficulty : context.Difficulty;
            var shareDiff         = stratumDifficulty;
            var ratio             = shareDiff / stratumDifficulty;

            var sentTargetInt  = new uint256(AionUtils.diffToTarget(context.Difficulty).HexToReverseByteArray());
            var sentTarget     = new BigInteger(sentTargetInt.ToBytes());
            var isLowDiffShare = sentTarget <= headerValue;

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

            var result = new Share
            {
                BlockHeight                 = (long)BlockTemplate.Height,
                IpAddress                   = worker.RemoteEndpoint?.Address?.ToString(),
                Miner                       = context.MinerName,
                Worker                      = context.WorkerName,
                UserAgent                   = context.UserAgent,
                NetworkDifficulty           = Difficulty,
                Difficulty                  = stratumDifficulty,
                IsBlockCandidate            = isBlockCandidate,
                TransactionConfirmationData = headerHash.ToHexString(),
            };

            if (isBlockCandidate)
            {
                // result.BlockReward = AionUtils.calculateReward((long) BlockTemplate.Height);
                result.BlockHash = headerHashReversed.ToHexString();
            }

            return(result, nonce, solution, BlockTemplate.HeaderHash, nTime);
        }