protected virtual (Share Share, string BlockHex) ProcessShareInternal( StratumClient worker, string extraNonce2, uint nTime, uint nonce, uint?versionBits) { var context = worker.ContextAs <BitcoinWorkerContext>(); var extraNonce1 = context.ExtraNonce1; // build coinbase var coinbase = SerializeCoinbase(extraNonce1, extraNonce2); Span <byte> coinbaseHash = stackalloc byte[32]; coinbaseHasher.Digest(coinbase, coinbaseHash); // hash block-header var headerBytes = SerializeHeader(coinbaseHash, nTime, nonce, context.VersionRollingMask, versionBits); Span <byte> headerHash = stackalloc byte[32]; headerHasher.Digest(headerBytes, headerHash, (ulong)nTime, BlockTemplate, coin, networkParams); var headerValue = new uint256(headerHash); // calc share-diff var shareDiff = (double)new BigRational(BitcoinConstants.Diff1, 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 / shareMultiplier, }; if (isBlockCandidate) { result.IsBlockCandidate = true; Span <byte> blockHash = stackalloc byte[32]; blockHasher.Digest(headerBytes, blockHash, nTime); result.BlockHash = blockHash.ToHexString(); var blockBytes = SerializeBlock(headerBytes, coinbase); var blockHex = blockBytes.ToHexString(); return(result, blockHex); } return(result, null); }
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); // hash block-header var headerBytes = SerializeHeader(nTime, extraNonceBytes, nonceInt); // 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); }
private (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); }
protected virtual BitcoinShare ProcessShareInternal(StratumClient worker, string extraNonce2, uint nTime, uint nonce) { var context = worker.GetContextAs <BitcoinWorkerContext>(); var extraNonce1 = 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 = new uint256(headerHash); // calc share-diff var shareDiff = (double)new BigRational(BitcoinConstants.Diff1, 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 BitcoinShare { BlockHeight = BlockTemplate.Height, BlockReward = rewardToPool.ToDecimal(MoneyUnit.BTC), NetworkDifficulty = Difficulty * shareMultiplier, Difficulty = stratumDifficulty, }; var blockBytes = SerializeBlock(headerBytes, coinbase); if (isBlockCandidate) { result.IsBlockCandidate = true; result.BlockHex = blockBytes.ToHexString(); result.BlockHash = blockHasher.Digest(headerBytes, nTime).ToHexString(); } return(result); }
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); }
private async Task <(Share Share, string nonce, string solution, string headerHash, string nTime)> ProcessShareInternal( StratumClient worker, string nonce, string nTime, string solution) { var context = worker.GetContextAs <AionWorkerContext>(); var solutionBytes = solution.HexToByteArray(); // serialize block-header var headerBytes = SerializeHeader(nonce); // verify solution if (!equihash.Verify210(headerBytes, solutionBytes)) { throw new StratumException(StratumError.Other, "invalid solution"); } // hash block-header var headerSolutionBytes = headerBytes.Concat(solutionBytes).ToArray(); var headerHash = headerHasher.Digest(headerSolutionBytes); var headerHashReversed = headerHash.ToReverseArray(); var headerBigInt = headerHashReversed.ToBigInteger(); var target = new BigInteger(blockTarget.ToBytes()); var isBlockCandidate = target > headerBigInt; // 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).HexToByteArray().ReverseArray()); var sentTarget = new BigInteger(sentTargetInt.ToBytes()); var isLowDiffShare = sentTarget <= headerBigInt; if (isLowDiffShare) { // Check if matched a previous varDiff before retarget if (context.VarDiff?.LastUpdate != null && context.PreviousDifficulty.HasValue) { var prevSentTargetInt = new uint256(AionUtils.diffToTarget(context.PreviousDifficulty.Value).HexToByteArray().ReverseArray()); var prevSentTargetBi = new BigInteger(prevSentTargetInt.ToBytes()); if (prevSentTargetBi <= headerBigInt) { stratumDifficulty = context.PreviousDifficulty.Value; } } else { 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); }
public void Digest(ReadOnlySpan <byte> data, Span <byte> result, params object[] extra) { upstream.Digest(data, result, extra); result.Reverse(); }