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);
            }
        }
Beispiel #2
0
        /// <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();
            });
        }
Beispiel #6
0
        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}";
        }
Beispiel #7
0
        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();
            });
        }
Beispiel #8
0
        /// <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);
            }
        }
Beispiel #10
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}");
     }
 }
Beispiel #11
0
        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);
            }
        }
Beispiel #12
0
        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>();
        }
Beispiel #13
0
 public static MinerConfig ReadConfigFile()
 {
     return(MinerConfig.ReadFromFile(@"..\XDaggerMinerWin\miner-config.json"));
 }
Beispiel #14
0
        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);
                }
            }
        }
Beispiel #15
0
        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();
        }