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) { 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 async Task <Block[]> ClassifyBlocksAsync(Block[] blocks) { Contract.RequiresNonNull(poolConfig, nameof(poolConfig)); Contract.RequiresNonNull(blocks, nameof(blocks)); var pageSize = 100; var pageCount = (int)Math.Ceiling(blocks.Length / (double)pageSize); var blockCache = new Dictionary <long, DaemonResponses.Block>(); var result = new List <Block>(); for (var i = 0; i < pageCount; i++) { // get a page full of blocks var page = blocks .Skip(i * pageSize) .Take(pageSize) .ToArray(); // get latest block var latestBlockResponses = await daemon.ExecuteCmdAllAsync <DaemonResponses.Block>(AionCommands.GetBlockByNumber, new[] { (object)"latest", true }); if (!latestBlockResponses.Any(x => x.Error == null && x.Response?.Height != null)) { break; } var latestBlockHeight = latestBlockResponses.First(x => x.Error == null && x.Response?.Height != null).Response.Height.Value; // execute batch var blockInfos = await FetchBlocks(blockCache, page.Select(block => (long)block.BlockHeight).ToArray()); for (var j = 0; j < blockInfos.Length; j++) { var blockInfo = blockInfos[j]; var block = page[j]; // extract confirmation data from stored block var mixHash = block.TransactionConfirmationData.Split(":").First(); var nonce = block.TransactionConfirmationData.Split(":").Last(); // update progress block.ConfirmationProgress = Math.Min(1.0d, (double)(latestBlockHeight - block.BlockHeight) / extraConfig.MinimumConfirmations); result.Add(block); // is it block mined by us? if (blockInfo.Miner == poolConfig.Address) { // mature? if (latestBlockHeight - block.BlockHeight >= (ulong)extraConfig.MinimumConfirmations) { block.Status = BlockStatus.Confirmed; block.ConfirmationProgress = 1; block.Reward = AionUtils.calculateReward((long)block.BlockHeight); if (extraConfig?.KeepTransactionFees == false && blockInfo.Transactions?.Length > 0) { block.Reward += await GetTxRewardAsync(blockInfo); // tx fees } logger.Info(() => $"[{LogCategory}] Unlocked block {block.BlockHeight} worth {FormatAmount(block.Reward)}"); } continue; } if (block.Status == BlockStatus.Pending && block.ConfirmationProgress > 0.75) { // we've lost this one block.Status = BlockStatus.Orphaned; block.Reward = 0; } } } return(result.ToArray()); }