Esempio n. 1
0
        protected virtual BitcoinShare ProcessShareInternal(StratumClient <BitcoinWorkerContext> worker, string extraNonce2, uint nTime, uint nonce)
        {
            var extraNonce1 = worker.Context.ExtraNonce1;

            // build coinbase
            var coinbase     = SerializeCoinbase(extraNonce1, extraNonce2);
            var coinbaseHash = coinbaseHasher.Digest(coinbase);

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

            // calc share-diff
            var shareDiff         = (double)new BigRational(BitcoinConstants.Diff1, 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, coinbase);

            result.BlockHex    = blockBytes.ToHexString();
            result.BlockHash   = blockHasher.Digest(headerBytes, nTime).ToHexString();
            result.BlockHeight = BlockTemplate.Height;
            result.BlockReward = rewardToPool.ToDecimal(MoneyUnit.BTC);
            result.Difficulty  = stratumDifficulty;

            return(result);
        }
Esempio n. 2
0
        protected virtual BitcoinShare ProcessShareInternal(string extraNonce1, string extraNonce2, uint nTime, uint nonce, double stratumDifficulty)
        {
            // build coinbase
            var coinbase     = SerializeCoinbase(extraNonce1, extraNonce2);
            var coinbaseHash = coinbaseHasher.Digest(coinbase);

            // build merkle-root
            var merkleRoot = mt.WithFirst(coinbaseHash)
                             .ToArray();

            // build block-header
            var blockHeader = new BlockHeader
            {
                Version        = (int)BlockTemplate.Version,
                Bits           = new Target(Encoders.Hex.DecodeData(BlockTemplate.Bits)),
                HashPrevBlock  = uint256.Parse(BlockTemplate.PreviousBlockhash),
                HashMerkleRoot = new uint256(merkleRoot),
                BlockTime      = DateTimeOffset.FromUnixTimeSeconds(nTime),
                Nonce          = nonce
            };

            // hash block-header
            var headerBytes = blockHeader.ToBytes();
            var headerHash  = headerHasher.Digest(headerBytes, (ulong)nTime);
            var headerValue = new BigInteger(headerHash);

            // calc share-diff
            var shareDiff = (double)new BigRational(BitcoinConstants.Diff1, headerValue) * shareMultiplier;
            var ratio     = shareDiff / stratumDifficulty;

            // test if share meets at least workers current difficulty
            if (ratio < 0.99)
            {
                throw new StratumException(StratumError.LowDifficultyShare, $"low difficulty share ({shareDiff})");
            }

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

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

            var blockBytes = SerializeBlock(headerBytes, coinbase);

            result.BlockHex    = blockBytes.ToHexString();
            result.BlockHash   = blockHasher.Digest(headerBytes, nTime).ToHexString();
            result.BlockHeight = BlockTemplate.Height;
            result.BlockReward = rewardToPool.ToDecimal(MoneyUnit.BTC);

            return(result);
        }
Esempio n. 3
0
        private async Task <(bool Accepted, string CoinbaseTransaction)> SubmitBlockAsync(BitcoinShare share)
        {
            // execute command batch
            var results = await daemon.ExecuteBatchAnyAsync(
                hasSubmitBlockMethod
                ?new DaemonCmd(BitcoinCommands.SubmitBlock, new[] { share.BlockHex })
                : new DaemonCmd(BitcoinCommands.GetBlockTemplate, new { mode = "submit", data = share.BlockHex }),
                new DaemonCmd(BitcoinCommands.GetBlock, new[] { share.BlockHash }));

            // did submission succeed?
            var submitResult = results[0];
            var submitError  = submitResult.Error?.Message ?? submitResult.Response?.ToString();

            if (!string.IsNullOrEmpty(submitError))
            {
                logger.Warn(() => $"[{LogCat}] Block {share.BlockHeight} submission failed with: {submitError}");
                return(false, null);
            }

            // was it accepted?
            var acceptResult = results[1];
            var block        = acceptResult.Response?.ToObject <Blocks>();
            var accepted     = acceptResult.Error == null && block?.Hash == share.BlockHash;

            return(accepted, block?.Transactions.FirstOrDefault());
        }
Esempio n. 4
0
        protected virtual async Task <(bool Accepted, string CoinbaseTransaction)> SubmitBlockAsync(BitcoinShare share)
        {
            // execute command batch
            var results = await daemon.ExecuteBatchAnyAsync(
                hasSubmitBlockMethod
                ?new DaemonCmd(BitcoinCommands.SubmitBlock, new[] { share.BlockHex })
                : new DaemonCmd(BitcoinCommands.GetBlockTemplate, new { mode = "submit", data = share.BlockHex }),
                new DaemonCmd(BitcoinCommands.GetBlock, new[] { share.BlockHash }));

            // did submission succeed?
            var submitResult = results[0];
            var submitError  = submitResult.Error?.Message ?? submitResult.Response?.ToString();

            if (!string.IsNullOrEmpty(submitError))
            {
                logger.Warn(() => $"[{LogCat}] Block {share.BlockHeight} submission failed with: {submitError}");
                notificationService.NotifyAdmin("Block submission failed", $"Block {share.BlockHeight} submission failed with: {submitError}");

                return(false, null);
            }

            // was it accepted?
            var acceptResult = results[1];
            var block        = acceptResult.Response?.ToObject <DaemonResponses.Block>();
            var accepted     = acceptResult.Error == null && block?.Hash == share.BlockHash;

            if (!accepted)
            {
                logger.Warn(() => $"[{LogCat}] Block {share.BlockHeight} submission failed for pool {poolConfig.Id} because block was not found after submission");
                notificationService.NotifyAdmin("Block submission failed", $"Block {share.BlockHeight} submission failed for pool {poolConfig.Id} because block was not found after submission");
            }

            return(accepted, block?.Transactions.FirstOrDefault());
        }