/// <summary> /// Encrypt math calculation with the current mining method /// </summary> /// <param name="calculation"></param> /// <returns></returns> private static string MakeEncryptedShare(string calculation, int idThread) { try { string encryptedShare = ClassUtility.StringToHexString(calculation + ClassMiningStats.CurrentBlockTimestampCreate); // Static XOR Encryption -> Key updated from the current mining method. encryptedShare = ClassUtility.EncryptXorShare(encryptedShare, ClassMiningStats.CurrentRoundXorKey.ToString()); // Dynamic AES Encryption -> Size and Key's from the current mining method and the current block key encryption. for (int i = 0; i < ClassMiningStats.CurrentRoundAesRound; i++) { encryptedShare = ClassUtility.EncryptAesShare(encryptedShare, ClassMiningStats.CurrentAesKeyBytes, ClassMiningStats.CurrentAesIvBytes, ClassMiningStats.CurrentRoundAesSize); } // Static XOR Encryption -> Key from the current mining method encryptedShare = ClassUtility.EncryptXorShare(encryptedShare, ClassMiningStats.CurrentRoundXorKey.ToString()); // Static AES Encryption -> Size and Key's from the current mining method. encryptedShare = ClassUtility.EncryptAesShare(encryptedShare, ClassMiningStats.CurrentAesKeyBytes, ClassMiningStats.CurrentAesIvBytes, ClassMiningStats.CurrentRoundAesSize); // Generate SHA512 HASH for the share. encryptedShare = ClassUtility.GenerateSHA512(encryptedShare); DictionaryMiningThread[idThread]++; // Calculated only from real activity. return(encryptedShare); } catch { return(ClassAlgoErrorEnumeration.AlgoError); } }
/// <summary> /// Start thread mining. /// </summary> private static async Task StartThreadMiningAsync(int idThread) { decimal minRange = Math.Round((ClassMiningStats.CurrentBlockDifficulty / ClassMiningConfig.MiningConfigThread) * (idThread - 1), 0); if (minRange <= 1) { minRange = 2; } decimal maxRange = Math.Round(((ClassMiningStats.CurrentBlockDifficulty / ClassMiningConfig.MiningConfigThread) * idThread), 0); ClassConsole.ConsoleWriteLine("Start mining thread id: " + idThread + " on mining job: " + ClassMiningStats.CurrentMiningDifficulty + " with range: " + minRange + "|" + maxRange, ClassConsoleEnumeration.IndexPoolConsoleBlueLog); var currentMiningJobIndication = ClassMiningStats.CurrentJobIndication; int currentBlockDifficultyLength = ClassMiningStats.CurrentMiningDifficulty.ToString().Length; while (ClassMiningNetwork.IsLogged && ThreadMiningRunning) { if (currentMiningJobIndication != ClassMiningStats.CurrentJobIndication) { minRange = Math.Round((ClassMiningStats.CurrentBlockDifficulty / ClassMiningConfig.MiningConfigThread) * (idThread - 1), 0); if (minRange <= 1) { minRange = 2; } maxRange = (Math.Round(((ClassMiningStats.CurrentBlockDifficulty / ClassMiningConfig.MiningConfigThread) * idThread), 0)); maxRange = Math.Round(maxRange, 0); currentMiningJobIndication = ClassMiningStats.CurrentJobIndication; ClassConsole.ConsoleWriteLine("Start mining thread id: " + idThread + " on mining job difficulty: " + ClassMiningStats.CurrentMiningDifficulty + " with range: " + minRange + "|" + maxRange, ClassConsoleEnumeration.IndexPoolConsoleBlueLog); currentBlockDifficultyLength = ClassMiningStats.CurrentMiningDifficulty.ToString().Length; } string firstNumber = string.Empty; string secondNumber = string.Empty; if (ClassUtils.GetRandomBetween(0, 100) >= ClassUtils.GetRandomBetween(0, 100)) { firstNumber = ClassUtility.GenerateNumberMathCalculation(minRange, maxRange, currentBlockDifficultyLength); } else { firstNumber = ClassUtility.GetRandomBetweenJob(minRange, maxRange).ToString(); } if (ClassUtils.GetRandomBetween(0, 100) >= ClassUtils.GetRandomBetween(0, 100)) { secondNumber = ClassUtility.GenerateNumberMathCalculation(minRange, maxRange, currentBlockDifficultyLength); } else { secondNumber = ClassUtility.GetRandomBetweenJob(minRange, maxRange).ToString(); } for (int i = 0; i < ClassUtility.RandomOperatorCalculation.Length; i++) { if (i < ClassUtility.RandomOperatorCalculation.Length) { #region Test unreverted calculation string calculation = firstNumber + " " + ClassUtility.RandomOperatorCalculation[i] + " " + secondNumber; decimal calculationResult = ClassUtility.ComputeCalculation(firstNumber, ClassUtility.RandomOperatorCalculation[i], secondNumber); if (calculationResult >= ClassMiningStats.CurrentMinRangeJob && calculationResult <= ClassMiningStats.CurrentBlockDifficulty) { if (calculationResult - Math.Round(calculationResult, 0) == 0) // Check if the result contain decimal places, if yes ignore it. { string encryptedShare = MakeEncryptedShare(calculation, (idThread - 1)); if (encryptedShare != ClassAlgoErrorEnumeration.AlgoError) { // Generate SHA512 hash for block hash indication. string hashEncryptedShare = ClassUtility.GenerateSHA512(encryptedShare); string hashEncryptedShareForPool = ClassUtility.EncryptXorShare(hashEncryptedShare, ClassMiningStats.CurrentJobKeyEncryption); hashEncryptedShareForPool = ClassUtility.HashJobToHexString(hashEncryptedShareForPool); if (ClassMiningStats.CurrentJobIndication.ContainsKey(hashEncryptedShareForPool) || hashEncryptedShare == ClassMiningStats.CurrentBlockIndication) { if (!DictionaryShareSubmittedCache.ContainsKey(hashEncryptedShareForPool)) { try { DictionaryShareSubmittedCache.Add(hashEncryptedShareForPool, calculation); } catch { } JObject share = new JObject { { "type", ClassMiningRequest.TypeSubmit }, { ClassMiningRequest.SubmitResult, calculationResult.ToString("F0") }, { ClassMiningRequest.SubmitFirstNumber, firstNumber }, { ClassMiningRequest.SubmitSecondNumber, secondNumber }, { ClassMiningRequest.SubmitOperator, ClassUtility.RandomOperatorCalculation[i] }, { ClassMiningRequest.SubmitShare, encryptedShare }, { ClassMiningRequest.SubmitHash, hashEncryptedShareForPool } }; await ClassMiningNetwork.SendPacketToPoolAsync(share.ToString(Formatting.None)).ConfigureAwait(false); } } } } else // Test reverted { #region Test reverted calculation calculation = secondNumber + " " + ClassUtility.RandomOperatorCalculation[i] + " " + firstNumber; calculationResult = ClassUtility.ComputeCalculation(secondNumber, ClassUtility.RandomOperatorCalculation[i], firstNumber); if (calculationResult >= ClassMiningStats.CurrentMinRangeJob && calculationResult <= ClassMiningStats.CurrentBlockDifficulty) { if (calculationResult - Math.Round(calculationResult, 0) == 0) // Check if the result contain decimal places, if yes ignore it. { string encryptedShare = MakeEncryptedShare(calculation, (idThread - 1)); if (encryptedShare != ClassAlgoErrorEnumeration.AlgoError) { // Generate SHA512 hash for block hash indication. string hashEncryptedShare = ClassUtility.GenerateSHA512(encryptedShare); string hashEncryptedShareForPool = ClassUtility.EncryptXorShare(hashEncryptedShare, ClassMiningStats.CurrentJobKeyEncryption); hashEncryptedShareForPool = ClassUtility.HashJobToHexString(hashEncryptedShareForPool); if (ClassMiningStats.CurrentJobIndication.ContainsKey(hashEncryptedShareForPool) || hashEncryptedShare == ClassMiningStats.CurrentBlockIndication) { if (!DictionaryShareSubmittedCache.ContainsKey(hashEncryptedShareForPool)) { try { DictionaryShareSubmittedCache.Add(hashEncryptedShareForPool, calculation); } catch { } JObject share = new JObject { { "type", ClassMiningRequest.TypeSubmit }, { ClassMiningRequest.SubmitResult, calculationResult.ToString("F0") }, { ClassMiningRequest.SubmitFirstNumber, secondNumber }, { ClassMiningRequest.SubmitSecondNumber, firstNumber }, { ClassMiningRequest.SubmitOperator, ClassUtility.RandomOperatorCalculation[i] }, { ClassMiningRequest.SubmitShare, encryptedShare }, { ClassMiningRequest.SubmitHash, hashEncryptedShareForPool } }; await ClassMiningNetwork.SendPacketToPoolAsync(share.ToString(Formatting.None)).ConfigureAwait(false); } } } } } #endregion } } else // Test reverted { #region Test reverted calculation calculation = secondNumber + " " + ClassUtility.RandomOperatorCalculation[i] + " " + firstNumber; calculationResult = ClassUtility.ComputeCalculation(secondNumber, ClassUtility.RandomOperatorCalculation[i], firstNumber); if (calculationResult >= ClassMiningStats.CurrentMinRangeJob && calculationResult <= ClassMiningStats.CurrentBlockDifficulty) { if (calculationResult - Math.Round(calculationResult, 0) == 0) // Check if the result contain decimal places, if yes ignore it. { string encryptedShare = MakeEncryptedShare(calculation, (idThread - 1)); if (encryptedShare != ClassAlgoErrorEnumeration.AlgoError) { // Generate SHA512 hash for block hash indication. string hashEncryptedShare = ClassUtility.GenerateSHA512(encryptedShare); string hashEncryptedShareForPool = ClassUtility.EncryptXorShare(hashEncryptedShare, ClassMiningStats.CurrentJobKeyEncryption); hashEncryptedShareForPool = ClassUtility.HashJobToHexString(hashEncryptedShareForPool); if (ClassMiningStats.CurrentJobIndication.ContainsKey(hashEncryptedShareForPool) || hashEncryptedShare == ClassMiningStats.CurrentBlockIndication) { if (!DictionaryShareSubmittedCache.ContainsKey(hashEncryptedShareForPool)) { try { DictionaryShareSubmittedCache.Add(hashEncryptedShareForPool, calculation); } catch { } JObject share = new JObject { { "type", ClassMiningRequest.TypeSubmit }, { ClassMiningRequest.SubmitResult, calculationResult.ToString("F0") }, { ClassMiningRequest.SubmitFirstNumber, secondNumber }, { ClassMiningRequest.SubmitSecondNumber, firstNumber }, { ClassMiningRequest.SubmitOperator, ClassUtility.RandomOperatorCalculation[i] }, { ClassMiningRequest.SubmitShare, encryptedShare }, { ClassMiningRequest.SubmitHash, hashEncryptedShareForPool } }; await ClassMiningNetwork.SendPacketToPoolAsync(share.ToString(Formatting.None)).ConfigureAwait(false); } } } } } #endregion } #endregion } } } ThreadMiningRunning = false; }
/// <summary> /// Handle packets received from pool. /// </summary> /// <param name="packet"></param> private static void HandleMiningPoolPacket(JObject jsonPacket) { try { switch (jsonPacket["type"].ToString().ToLower()) { case ClassMiningRequest.TypeLogin: if (jsonPacket.ContainsKey(ClassMiningRequest.TypeLoginWrong)) { ClassConsole.ConsoleWriteLine("Wrong login/wallet address, please check your setting. Disconnect now.", ClassConsoleEnumeration.IndexPoolConsoleRedLog); DisconnectMiner(); } else { if (jsonPacket.ContainsKey(ClassMiningRequest.TypeLoginOk)) { ClassConsole.ConsoleWriteLine("Login/Wallet Address accepted by the pool. Waiting job.", ClassConsoleEnumeration.IndexPoolConsoleGreenLog); } } break; case ClassMiningRequest.TypeKeepAlive: LastPacketReceived = DateTimeOffset.Now.ToUnixTimeSeconds(); break; case ClassMiningRequest.TypeJob: LastPacketReceived = DateTimeOffset.Now.ToUnixTimeSeconds(); IsLogged = true; ClassMiningStats.CurrentBlockId = int.Parse(jsonPacket[ClassMiningRequest.TypeBlock].ToString()); ClassMiningStats.CurrentBlockTimestampCreate = jsonPacket[ClassMiningRequest.TypeBlockTimestampCreate].ToString(); ClassMiningStats.CurrentBlockKey = jsonPacket[ClassMiningRequest.TypeBlockKey].ToString(); ClassMiningStats.CurrentBlockIndication = jsonPacket[ClassMiningRequest.TypeBlockIndication].ToString(); ClassMiningStats.CurrentBlockDifficulty = decimal.Parse(jsonPacket[ClassMiningRequest.TypeBlockDifficulty].ToString()); var currentJobIndicationSplit = jsonPacket[ClassMiningRequest.TypeJobIndication].ToString().Split(new[] { ";" }, StringSplitOptions.None); var dictionaryJobIndication = new Dictionary <string, int>(); string currentJobIndication = string.Empty; int counterJob = 0; foreach (var jobIndication in currentJobIndicationSplit) { if (jobIndication != null) { if (!string.IsNullOrEmpty(jobIndication)) { if (jobIndication.Length > 1) { counterJob++; dictionaryJobIndication.Add(jobIndication, counterJob); currentJobIndication += jobIndication; } } } } ClassMiningStats.CurrentJobIndicationMinimized = ClassUtility.GenerateSHA512(currentJobIndication); ClassMiningStats.CurrentJobIndication = dictionaryJobIndication; ClassMiningStats.CurrentMinRangeJob = decimal.Parse(jsonPacket[ClassMiningRequest.TypeMinRange].ToString()); ClassMiningStats.CurrentMaxRangeJob = decimal.Parse(jsonPacket[ClassMiningRequest.TypeMaxRange].ToString()); ClassMiningStats.CurrentMethodName = jsonPacket[ClassMiningRequest.TypeJobMiningMethodName].ToString(); ClassMiningStats.CurrentRoundAesRound = int.Parse(jsonPacket[ClassMiningRequest.TypeJobMiningMethodAesRound].ToString()); ClassMiningStats.CurrentRoundAesSize = int.Parse(jsonPacket[ClassMiningRequest.TypeJobMiningMethodAesSize].ToString()); ClassMiningStats.CurrentRoundAesKey = jsonPacket[ClassMiningRequest.TypeJobMiningMethodAesKey].ToString(); ClassMiningStats.CurrentRoundXorKey = int.Parse(jsonPacket[ClassMiningRequest.TypeJobMiningMethodXorKey].ToString()); ClassMiningStats.CurrentJobKeyEncryption = jsonPacket[ClassMiningRequest.TypeJobKeyEncryption].ToString(); int totalShareToFound = ClassMiningStats.CurrentJobIndication.Count; if (jsonPacket.ContainsKey(ClassMiningRequest.TypeJobDifficulty)) { ClassMiningStats.CurrentMiningDifficulty = decimal.Parse(jsonPacket[ClassMiningRequest.TypeJobDifficulty].ToString()); } using (var pdb = new PasswordDeriveBytes(ClassMiningStats.CurrentBlockKey, Encoding.UTF8.GetBytes(ClassMiningStats.CurrentRoundAesKey))) { ClassMiningStats.CurrentAesKeyBytes = pdb.GetBytes(ClassMiningStats.CurrentRoundAesSize / 8); ClassMiningStats.CurrentAesIvBytes = pdb.GetBytes(ClassMiningStats.CurrentRoundAesSize / 8); } ClassMining.ProceedMining(); ClassConsole.ConsoleWriteLine("New Mining Job: " + ClassMiningStats.CurrentJobIndicationMinimized + " | Job Difficulty: " + ClassMiningStats.CurrentMiningDifficulty + " | Block ID: " + ClassMiningStats.CurrentBlockId + " | Block Difficulty: " + ClassMiningStats.CurrentBlockDifficulty + " | Block Hash Indication: " + ClassMiningStats.CurrentBlockIndication, ClassConsoleEnumeration.IndexPoolConsoleMagentaLog); ClassConsole.ConsoleWriteLine("Mining Job range received: " + ClassMiningStats.CurrentMinRangeJob + "|" + ClassMiningStats.CurrentMaxRangeJob, ClassConsoleEnumeration.IndexPoolConsoleMagentaLog); ClassConsole.ConsoleWriteLine("Total Share(s) to Found: " + totalShareToFound, ClassConsoleEnumeration.IndexPoolConsoleMagentaLog); break; case ClassMiningRequest.TypeShare: LastPacketReceived = DateTimeOffset.Now.ToUnixTimeSeconds(); switch (jsonPacket[ClassMiningRequest.TypeResult].ToString().ToLower()) { case ClassMiningRequest.TypeResultShareOk: ClassMiningStats.TotalGoodShare++; ClassConsole.ConsoleWriteLine("Good Share ! [Total = " + ClassMiningStats.TotalGoodShare + "]", ClassConsoleEnumeration.IndexPoolConsoleGreenLog); ClassMiningStats.TotalInvalidShare = 0; break; case ClassMiningRequest.TypeResultShareInvalid: ClassMiningStats.TotalInvalidShare++; if (ClassMiningStats.TotalInvalidShare >= ClassMiningConfig.MiningConfigMaxInvalidShare) { DisconnectMiner(); ClassMiningStats.TotalInvalidShare = 0; } ClassConsole.ConsoleWriteLine("Invalid Share ! [Total = " + ClassMiningStats.TotalInvalidShare + "]", ClassConsoleEnumeration.IndexPoolConsoleRedLog); break; case ClassMiningRequest.TypeResultShareDuplicate: ClassMiningStats.TotalDuplicateShare++; ClassConsole.ConsoleWriteLine("Duplicate Share ! [Total = " + ClassMiningStats.TotalDuplicateShare + "]", ClassConsoleEnumeration.IndexPoolConsoleYellowLog); break; case ClassMiningRequest.TypeResultShareLowDifficulty: ClassMiningStats.TotalLowDifficultyShare++; ClassConsole.ConsoleWriteLine("Low Difficulty Share ! [Total = " + ClassMiningStats.TotalLowDifficultyShare + "]", ClassConsoleEnumeration.IndexPoolConsoleRedLog); break; } break; } } catch { } }