public override CommandResult Execute(string parameter) { logger.Trace("ServiceCommand executes with parameter: " + parameter); minerConfig = MinerConfig.GetInstance(); serviceProvider = ComposeServiceProvider(minerConfig.InstanceType); serviceInstanceId = minerConfig.InstanceId; logger.Trace($"InstanceType: {minerConfig.InstanceType}. InstanceId: {serviceInstanceId}"); string operationName = parameter; switch (operationName) { case "start": return(Start()); case "stop": return(Stop()); case "install": return(Install()); case "uninstall": return(Uninstall()); case "detect": return(Detect()); default: throw new TargetExecutionException(DaemonErrorCode.COMMAND_PARAM_ERROR, "Unknown operation type for service: " + operationName); } }
/// <summary> /// Initializes a new instance of the <see cref="PoolConfig"/> class. /// </summary> /// <param name="config">The configuration.</param> /// <param name="coinConfig"></param> public PoolConfig(dynamic config, ICoinConfig coinConfig) { try { Enabled = config.enabled ? config.enabled : false; if (Enabled == false) // if the configuration is not enabled { return; // just skip reading rest of the parameters. } Coin = coinConfig; // assign the coin config. // load the sections. Daemon = new DaemonConfig(config.daemon); Meta = new MetaConfig(config.meta); Wallet = new WalletConfig(config.wallet); Rewards = new RewardsConfig(config.rewards); Payments = new PaymentConfig(config.payments); Miner = new MinerConfig(config.miner); Job = new JobConfig(config.job); Stratum = new StratumServerConfig(config.stratum); Banning = new BanConfig(config.banning); Storage = new RedisConfig(config.storage.redis); Vanilla = new VanillaServerConfig(config.vanilla); Valid = true; } catch (Exception e) { Valid = false; Log.Logger.ForContext <PoolConfig>().Error(e, "Error loading pool configuration"); } }
public void TestConfigureAnotherInstanceId() { string result = ExecuteDaemon("-c \"{ 'XDaggerWallet':'1Nwa0TCr5umw5ZLAvKmHCl+SJDP21dyL', 'XDaggerPoolAddress':'xey.ti:13654', 'DeviceId':'p_0_d_0','AutoDecideInstanceId':'true' }\""); Assert.AreEqual(0, ParseResultCode(result), "Configure command should success."); try { result = ExecuteDaemon("-s install"); Assert.AreEqual(0, ParseResultCode(result), "Service should be installed."); Assert.IsTrue(IsServiceExist(XDaggerServiceName, 0), "Found service in Windows Services."); result = ExecuteDaemon("-c \"{ 'AutoDecideInstanceId':'true' }\""); ConfigureOutput output = ParseResultData <ConfigureOutput>(result); Assert.AreEqual(output.InstanceId, 1, "InstanceId should be 1."); MinerConfig config = ReadConfigFile(); Assert.IsTrue(config.InstanceType == MinerConfig.InstanceTypes.XDagger, "InstanceType is XDagger."); Assert.AreEqual(config.InstanceId, 1, "InstanceId in config should be 1."); } finally { TryUninstallService("XDaggerMinerWin", 0); } }
private void OnTimerWork(object sender, ElapsedEventArgs e) { minerEventLog.WriteInformation(0, "Triggered by Timer."); MinerConfig config = MinerConfig.ReadFromFile(); minerManager.DoMining(config.PoolAddress, config.WalletAddress); }
public EthMinerService() { InitializeComponent(); minerConfig = MinerConfig.GetInstance(); namedPipeServerTask = new Task(() => { NamedPipeServerMain(); }); }
private static void SetActiveMiner(MinerConfig newMinerConfig) { _currentMiningConfig = newMinerConfig; PrettyConsole.WriteLine($"Starting {_currentMiningConfig.Name} - {_currentMiningConfig.ExeLocation} {_currentMiningConfig.CommandLineParameters}"); KillMiner(); var match = WalletRegex.Match(newMinerConfig.CommandLineParameters); _walletPrefix = match.Groups[1].Value; _wallet = match.Groups[2].Value; //_workerName = string.IsNullOrEmpty(match.Groups[3].Value.Trim()) ? string.Empty : $"{match.Groups[4].Value}"; }
public MinerService() { InitializeComponent(); config = MinerConfig.ReadFromFile(); minerManager = new MinerManager(config.IsFakeRun); minerEventLog = new MinerEventLog(); minerManager.SetLogger(minerEventLog); minerEventLog.WriteLog(0, 0, "MinerService Started."); namedPipeServerTask = new Task(() => { NamedPipeServerMain(); }); }
/// <summary> /// Initializes a new instance of the <see cref="PoolConfig"/> class. /// </summary> /// <param name="config">The configuration.</param> /// <param name="coinConfig"></param> public PoolConfig(dynamic config, ICoinConfig coinConfig) { try { _logger = Log.ForContext <PoolConfig>().ForContext("Component", coinConfig.Name); Enabled = config.enabled ? config.enabled : false; if (Enabled == false) // if the configuration is not enabled { return; // just skip reading rest of the parameters. } Coin = coinConfig; // assign the coin config. // load the sections. Daemon = new DaemonConfig(config.daemon); Meta = new MetaConfig(config.meta); Wallet = new WalletConfig(config.wallet); Rewards = new RewardsConfig(config.rewards); Payments = new PaymentConfig(config.payments); Miner = new MinerConfig(config.miner); Job = new JobConfig(config.job); Stratum = new StratumServerConfig(config.stratum); Banning = new BanConfig(config.banning); Storage = new StorageConfig(config.storage); Vanilla = new VanillaServerConfig(config.vanilla); // process extra checks if (Storage.Layer is MposStorageLayerConfig) { if (Payments.Enabled) { Payments.Disable(); _logger.Information("Disabled payments processor as it can not be enabled when MPOS mode is on"); } } Valid = true; } catch (Exception e) { Valid = false; _logger.Error(e, "Error loading pool configuration"); } }
public void TestConfigureUpdateInstanceType() { string result = ExecuteDaemon("-c \"{ 'XDaggerWallet':'1Nwa0TCr5umw5ZLAvKmHCl+SJDP21dyL', 'XDaggerPoolAddress':'xey.ti:13654', 'DeviceId':'p_0_d_0','AutoDecideInstanceId':'true' }\""); Assert.AreEqual(ParseResultCode(result), 0, "Configure command should success."); try { result = ExecuteDaemon("-s install"); Assert.AreEqual(ParseResultCode(result), 0, "Service should be installed."); Assert.IsTrue(IsServiceExist(XDaggerServiceName, 0), "Found service in Windows Services."); result = ExecuteDaemon("-c \"{ 'EthPoolAddress':'stratum1tcp://0x73037FE73337D16D799c64632C1c79C19C8A85E6eth.f2pool.com:8008', 'AutoDecideInstanceId':'true' }\""); Assert.IsTrue(IsServiceExist(XDaggerServiceName, 0), "Service is not changed after configuration command."); ConfigureOutput output = ParseResultData <ConfigureOutput>(result); Assert.AreEqual(output.InstanceId, 0, "InstanceId should be 0."); MinerConfig config = ReadConfigFile(); Assert.IsTrue(config.InstanceType == MinerConfig.InstanceTypes.XDagger, "InstanceType is XDagger."); Assert.AreEqual(config.InstanceId, 0, "InstanceId in config should be 0."); Assert.IsTrue(config.UpdatedInstanceType == MinerConfig.InstanceTypes.Eth, "UpdatedInstanceType is XDagger."); Assert.AreEqual(config.UpdatedInstanceId, 0, "UpdatedInstanceId in config should be 0."); result = ExecuteDaemon("-s start"); Assert.IsFalse(IsServiceExist(XDaggerServiceName, 0), "XDagger service should be uninstalled."); Assert.IsTrue(IsServiceExist(XDaggerEthServiceName, 0), "XDagger Eth service should be installed."); config = ReadConfigFile(); Assert.IsTrue(config.InstanceType == MinerConfig.InstanceTypes.Eth, "InstanceType is XDagger."); Assert.AreEqual(config.InstanceId, 0, "InstanceId in config should be 0."); Assert.IsTrue(config.UpdatedInstanceType == null, "UpdatedInstanceType is null."); Assert.AreEqual(config.UpdatedInstanceId, null, "UpdatedInstanceId in config should be null."); } finally { TryUninstallService("XDaggerMinerWin", 0); } }
private static void RunMiner(string programName, MinerConfig minerConfig) { try { var process = new Process { StartInfo = new ProcessStartInfo { FileName = programName, Arguments = minerConfig.Parameters, WorkingDirectory = minerConfig.ProgramFolder } }; process.Start(); process.PriorityClass = ProcessPriorityClass.High; Console.WriteLine($"{programName} started!"); } catch (Exception e) { FileLogger.LogInfo($"Starting {programName} failed! Error: {Environment.NewLine}{e}"); } }
public override CommandResult Execute(string parameter) { try { ServiceProvider serviceProvider = ComposeServiceProvider(MinerConfig.GetInstance().InstanceType); int instanceId = MinerConfig.GetInstance().InstanceId; serviceInstance = serviceProvider.AquaireInstance(instanceId); ReportOutput outputResult = new ReportOutput(); outputResult.Status = ReportOutput.StatusEnum.Unknown; if (!serviceInstance.IsServiceExist()) { outputResult.Status = ReportOutput.StatusEnum.NotInstalled; } else if (!serviceInstance.IsServiceRunning()) { outputResult.Status = ReportOutput.StatusEnum.Stopped; } else { // Retrieve the miner status from NamedPipe QueryServiceStatusByNamedPipe(outputResult); } return(CommandResult.CreateResult(outputResult)); } catch (TargetExecutionException ex) { throw ex; } catch (Exception ex) { throw new TargetExecutionException(DaemonErrorCode.UNKNOWN_ERROR, ex); } }
public void Init(ContainerBuilder builder) { var minerConfig = MinerConfig.Default; if (NodeConfig.Instance.IsMiner) { minerConfig = new MinerConfig { CoinBase = Address.LoadHex(NodeConfig.Instance.NodeAccount) }; } minerConfig.ChainId = new Hash() { Value = ByteString.CopyFrom(ByteArrayHelpers.FromHexString(ChainConfig.Instance.ChainId)) }; builder.RegisterModule(new MinerRpcAutofacModule()); builder.RegisterType <ClientManager>().SingleInstance().OnActivated(mc => { mc.Instance.Init(dir: ApplicationHelpers.GetDefaultConfigPath()); } ); builder.RegisterType <ServerManager>().SingleInstance().OnActivated(mc => { mc.Instance.Init(ApplicationHelpers.GetDefaultConfigPath()); } ); builder.RegisterModule(new MinerAutofacModule(minerConfig)); var txPoolConfig = TxPoolConfig.Default; txPoolConfig.FeeThreshold = 0; txPoolConfig.PoolLimitSize = TransactionPoolConfig.Instance.PoolLimitSize; txPoolConfig.Maximal = TransactionPoolConfig.Instance.Maximal; txPoolConfig.EcKeyPair = TransactionPoolConfig.Instance.EcKeyPair; builder.RegisterInstance(txPoolConfig).As <ITxPoolConfig>(); }
public static MinerConfig ReadConfigFile() { return(MinerConfig.ReadFromFile(@"..\XDaggerMinerWin\miner-config.json")); }
public override CommandResult Execute(string parameter) { // Update the configuration ConfigureParameter configParameters = null; isInstanceUpdated = false; try { configParameters = JsonConvert.DeserializeObject <ConfigureParameter>(parameter); } catch (FormatException) { throw new TargetExecutionException(DaemonErrorCode.COMMAND_PARAM_ERROR, "The format of the Configuration content is not valid Json."); } MinerConfig config = MinerConfig.ReadFromFile(); if (!string.IsNullOrEmpty(configParameters.DeviceId) || !string.IsNullOrEmpty(configParameters.DeviceName)) { MinerManager minerManager = new MinerManager(); List <MinerDevice> deviceList = minerManager.GetAllMinerDevices(); bool deviceFound = false; foreach (MinerDevice device in deviceList) { if (device.IsMatchId(configParameters.DeviceId) || string.Equals(device.GetDisplayName(), configParameters.DeviceName)) { config.Device = new MinerConfigDevice(device.GetDeviceId(), device.GetDisplayName(), device.GetDeviceVersion(), device.GetDriverVersion()); deviceFound = true; break; } } if (!deviceFound) { throw new TargetExecutionException(DaemonErrorCode.CONFIG_DEVICE_NOT_FOUND, string.Format("Did not find the device matches DeviceId=[{0}] or DeviceName=[{1}]", configParameters.DeviceId, configParameters.DeviceName)); } } if ((!string.IsNullOrEmpty(configParameters.XDaggerWallet) || !string.IsNullOrEmpty(configParameters.XDaggerPoolAddress)) && !string.IsNullOrEmpty(configParameters.EthPoolAddress)) { throw new TargetExecutionException(DaemonErrorCode.CONFIG_ONLY_ONE_INSTANCE_TYPE_ALLOWED, "Only one type of miner instance is allowed."); } if (configParameters.InstanceId.HasValue && configParameters.AutoDecideInstanceId) { throw new TargetExecutionException(DaemonErrorCode.COMMAND_PARAM_ERROR, "Cannot specify InstanceId while AutoDecideInstanceId is used."); } InstanceTypes?proposedInstanceType = null; if (!string.IsNullOrEmpty(configParameters.XDaggerWallet)) { string wallet = configParameters.XDaggerWallet.Trim(); // TODO: Should validate the Wallet address first if (false) { throw new TargetExecutionException(DaemonErrorCode.CONFIG_WALLET_FORMET_ERROR, string.Format("Wallet format is not correct. Wallet=[{0}]", configParameters.XDaggerWallet)); } if (false) { throw new TargetExecutionException(DaemonErrorCode.CONFIG_WALLET_NOT_FOUND, string.Format("Wallet cannot be found. Wallet=[{0}]", configParameters.XDaggerWallet)); } if (config.XDaggerMiner == null) { config.XDaggerMiner = new XDaggerMinerConfig(); } proposedInstanceType = MinerConfig.InstanceTypes.XDagger; config.XDaggerMiner.WalletAddress = wallet; } if (!string.IsNullOrEmpty(configParameters.XDaggerPoolAddress)) { string poolAddress = configParameters.XDaggerPoolAddress.Trim(); // TODO: Should validate the Wallet address first if (false) { throw new TargetExecutionException(DaemonErrorCode.CONFIG_WALLET_FORMET_ERROR, string.Format("Wallet format is not correct. Wallet=[{0}]", configParameters.XDaggerWallet)); } if (false) { throw new TargetExecutionException(DaemonErrorCode.CONFIG_WALLET_NOT_FOUND, string.Format("Wallet cannot be found. Wallet=[{0}]", configParameters.XDaggerWallet)); } if (config.XDaggerMiner == null) { config.XDaggerMiner = new XDaggerMinerConfig(); } proposedInstanceType = MinerConfig.InstanceTypes.XDagger; config.XDaggerMiner.PoolAddress = poolAddress; } if (!string.IsNullOrEmpty(configParameters.EthPoolAddress)) { string ethPoolAddress = configParameters.EthPoolAddress.Trim(); // TODO: Should validate the Wallet address first if (false) { throw new TargetExecutionException(DaemonErrorCode.CONFIG_WALLET_FORMET_ERROR, string.Format("Wallet format is not correct. Wallet=[{0}]", configParameters.XDaggerWallet)); } if (false) { throw new TargetExecutionException(DaemonErrorCode.CONFIG_WALLET_NOT_FOUND, string.Format("Wallet cannot be found. Wallet=[{0}]", configParameters.XDaggerWallet)); } if (config.EthMiner == null) { config.EthMiner = new EthMinerConfig(); } proposedInstanceType = MinerConfig.InstanceTypes.Eth; config.EthMiner.PoolAddress = ethPoolAddress; } ServiceProvider currentServiceProvider = ServiceProvider.GetServiceProvider(config.InstanceType); ServiceInstance currentServiceInstance = currentServiceProvider?.AquaireInstance(config.InstanceId); // Check the change of instance Type, if the service is already installed, put the new instance type into updated_instance_type, and detect new updated_instance_id if (currentServiceInstance != null && currentServiceInstance.IsServiceExist()) { // Put the type into updated_instance_type if (proposedInstanceType == null) { if (config.UpdatedInstanceType != null && configParameters.InstanceId != null) { config.UpdatedInstanceId = configParameters.InstanceId; } } else if (proposedInstanceType != config.InstanceType) { isInstanceUpdated = true; config.UpdatedInstanceType = proposedInstanceType; config.UpdatedInstanceId = DecideInstanceId(configParameters, proposedInstanceType.Value, true); } } else if (proposedInstanceType != null) { if (configParameters.AutoDecideInstanceId || (config.InstanceType != InstanceTypes.Unset && proposedInstanceType != config.InstanceType)) { isInstanceUpdated = true; } config.InstanceType = proposedInstanceType.Value; config.InstanceId = DecideInstanceId(configParameters, proposedInstanceType.Value, false) ?? config.InstanceId; // Clear the updated ones config.UpdatedInstanceId = null; config.UpdatedInstanceType = null; } // Save all of the changes into config file int retryTimes = 0; while (true) { try { config.SaveToFile(); if (isInstanceUpdated) { return(CommandResult.CreateResult(ConfigureOutput.Create(config.UpdatedInstanceId ?? config.InstanceId))); } else { return(CommandResult.OKResult()); } } catch (Exception ex) { if (retryTimes++ < IntermediateFailureRetryTimes) { Thread.Sleep(IntermediateFailureRetryPeriod); continue; } throw new TargetExecutionException(DaemonErrorCode.UNKNOWN_ERROR, ex.Message); } } }
static void Main() { Initialize(); #region Error Mode //Prevent error dialog popups, this prevents the miner sub process from hanging by a windows error popup during a crash NativeMethods.SetErrorMode(NativeMethods.ErrorModes.SemFailcriticalerrors | NativeMethods.ErrorModes.SemNogpfaulterrorbox); #endregion #region Console Hooks //Hook Console to catch Close Event Handler = ConsoleEventCallback; NativeMethods.SetConsoleCtrlHandler(Handler, true); Console.CancelKeyPress += delegate(object sender, ConsoleCancelEventArgs e) { e.Cancel = true; _running = false; PrettyConsole.WriteLine("Gracefully exiting...", ConsoleColor.Magenta); }; #endregion Startup: try { ConnectToMonitoringSocket(); //Every minute the miner is running, it updates this file with how many minutes it has mined % MinutesInRotation var text = ""; try { text = File.ReadAllText(MiningMinuteFile); } catch (Exception ex) { Log.Warning(ex); } if (!int.TryParse(text, out _miningMinute)) { Log.Warning($"Unable to read Mining Minute, defaulting to 0. Text received from {MiningMinuteFile}: {text}"); } int currentMinute = -1; var freshStart = new List <string> { "XzonControlPanel" }; foreach (MinerConfig miner in _miners) { var exeName = Path.GetFileNameWithoutExtension(miner.ExeLocation); if (!freshStart.Contains(exeName)) { freshStart.Add(exeName); } } foreach (var p in freshStart) { ProcessHelper.KillProcess(p); } Thread.Sleep(1000); PrettyConsole.Write("Max Allowed GPU Temperature is "); PrettyConsole.WriteLine($"{MaxTemp}°c", ConsoleColor.Red); PrettyConsole.WriteLine(); Log.Warning("Miner Has Started"); //Main Loop while (_running) { Temperature.Refresh(); #region Scheduling if (DateTime.Now.Hour * 60 + DateTime.Now.Minute != currentMinute && !_paused) { //Minute changed, increment _miningMinute = (_miningMinute + 1) % MinutesInRotation; UpdateMiningMinute(_miningMinute); currentMinute = DateTime.Now.Hour * 60 + DateTime.Now.Minute; PrettyConsole.WriteLine($"Current Minute: {_miningMinute}", ConsoleColor.DarkYellow); //Check if it is time to use the next miner config in the schedule MinerConfig newMinerConfig = _miners[0]; foreach (MinerConfig miner in _miners) { if (miner.StartMinute <= _miningMinute) { newMinerConfig = miner; } else { PrettyConsole.WriteLine($"Will start {miner.Name} at minute {miner.StartMinute}", ConsoleColor.DarkYellow); } } if (!newMinerConfig.Equals(_currentMiningConfig)) { SetActiveMiner(newMinerConfig); } } #endregion VerifyProcesses(); if (!_running) { break; } if (_paused) { Log.Informational("Miner is paused"); //If reboot after paused X minutes is set, reboot after X minutes if (RebootAfterPausedXMinutes > 0 && _pausedTime != null) { if (DateTime.Now > _pausedTime.Value.AddMinutes(RebootAfterPausedXMinutes)) { Log.Warning("Rebooting Machine"); Process.Start("shutdown.exe", "-r -t 30"); _running = false; } else { Log.Informational($"Rebooting machine in {_pausedTime.Value.AddMinutes(RebootAfterPausedXMinutes).Subtract(DateTime.Now).TotalSeconds} seconds", true); PrettyConsole.Write("Rebooting machine in "); PrettyConsole.Write($"{_pausedTime.Value.AddMinutes(RebootAfterPausedXMinutes).Subtract(DateTime.Now).TotalSeconds}", ConsoleColor.Yellow); PrettyConsole.WriteLine(" seconds"); } } } List <Gpu> gpus = new List <Gpu>(); List <Cpu> cpus = new List <Cpu>(); if (Temperature.GpuTemperatures == null) { Log.Warning("Unable to read GPU Temperatures, killing miner"); Pause(); KillMiner(); continue; } foreach (var temp in Temperature.CpuTemperatures) { PrettyConsole.Write($"{temp.InstanceName} ({temp.InstanceId}): "); PrettyConsole.WriteLine($"{temp.CurrentValue}°c", ConsoleColor.Cyan); cpus.Add(new Cpu { Color = "Cyan", Id = temp.InstanceId, Name = temp.InstanceName, Temp = (int)temp.CurrentValue }); } foreach (var temp in Temperature.GpuTemperatures) { PrettyConsole.Write($"{temp.InstanceName} ({temp.InstanceId}): "); var outputColor = ConsoleColor.Cyan; if (temp.CurrentValue >= MaxTemp) { outputColor = ConsoleColor.Red; PrettyConsole.Write($"{temp.CurrentValue}", outputColor); PrettyConsole.Write(@"°c"); } else if (temp.CurrentValue >= WarningTemp) { outputColor = ConsoleColor.Yellow; PrettyConsole.Write($"{temp.CurrentValue}", outputColor); PrettyConsole.Write(@"°c"); } else if (Math.Abs(temp.CurrentValue) < 1) { //Check if GPU went offline, if it did its reported temperature is 0, check for <1 because floating point numbers doing their thing outputColor = ConsoleColor.Red; PrettyConsole.Write($"{temp.CurrentValue}", outputColor); PrettyConsole.Write(@"°c"); Log.Error($"GPU {temp.InstanceName} ({temp.InstanceId}) Went Offline."); KillMiner(); Pause(); } else { PrettyConsole.Write($"{temp.CurrentValue}", outputColor); PrettyConsole.Write(@"°c"); } decimal gpuHr = -1; try { int gpuId; if (int.TryParse(temp.InstanceId.Substring(temp.InstanceId.LastIndexOf("/", StringComparison.Ordinal) + 1), out gpuId)) { lock (RecentGpuHashrates) { if (RecentGpuHashrates.ContainsKey(gpuId) && RecentGpuHashrates[gpuId].Count > 0) { gpuHr = decimal.Round(RecentGpuHashrates[gpuId].Average(), 2); PrettyConsole.Write($" ({gpuHr} {_units}/s)", ConsoleColor.Gray); } } } } catch (Exception) { //Do nothing } finally { PrettyConsole.WriteLine(); } gpus.Add(new Gpu { Color = outputColor.ToString(), Name = temp.InstanceName, Id = temp.InstanceId, Temp = (int)temp.CurrentValue, Rate = gpuHr }); if (temp.CurrentValue > MaxTemp) { Log.Error($"Killing miner, GPU Temperature is {temp.CurrentValue}°c but the max is set for {MaxTemp}°c"); //Hard shut down //Exit(1); //Soft shut down KillMiner(); Pause(); } } //Check average hash rate decimal averageHashrate = 0; ConsoleColor hashrateColor = ConsoleColor.Red; if (RecentHashrates.Count > 0) { Queue <decimal> localQueue = new Queue <decimal>(RecentHashrates); averageHashrate = decimal.Round(localQueue.Average(), 3); hashrateColor = ConsoleColor.Green; if (averageHashrate < _currentMiningConfig.HashrateError) { hashrateColor = ConsoleColor.Red; if (localQueue.Count == TotalReadingsToAverage) { var error = $"Average Hashrate {averageHashrate} dropped below configured error rate ({_currentMiningConfig.HashrateError}). Killing miner."; Log.Error(error); KillMiner(); } } else if (averageHashrate < _currentMiningConfig.HashrateWarning) { hashrateColor = ConsoleColor.Yellow; if (localQueue.Count == TotalReadingsToAverage) { Log.Warning($"Average Hashrate {averageHashrate} dropped below configured warning rate {_currentMiningConfig.HashrateWarning}."); } } if (localQueue.Count > 0) { PrettyConsole.Write(@"Current Average Hashrate: "); PrettyConsole.Write($"{averageHashrate} {_units}/s", hashrateColor); PrettyConsole.WriteLine(); } PrettyConsole.Write(@"Solutions Found: "); PrettyConsole.Write($"{_solutionsFound}", _solutionsFound > 0 ? ConsoleColor.Green : ConsoleColor.Yellow); if (_rejectedSolutions > 0) { PrettyConsole.Write(@". Rejected: "); PrettyConsole.Write($"{_rejectedSolutions}", ConsoleColor.Red); } PrettyConsole.WriteLine(@"."); } UpdateMonitoringSockets(gpus, cpus, averageHashrate, hashrateColor); //foreach (var config in _miners) //{ // PrettyConsole.WriteLine($"({config.Wallet}){WalletHelper.GetWalletBalance(config.CurrencyCode, config.Wallet)}", ConsoleColor.DarkGreen); //} Thread.Sleep(10000); if (File.Exists("stop.txt")) { File.Delete("stop.txt"); _running = false; } } } catch (Exception ex) { Log.Error(ex); if (_running) { Log.Warning(ex); Log.Informational("Attempting to restart from the beginning..."); goto Startup; } } KillMiner(); Exit(); }