feat(mining): auto-balance driver, per-pool algo, live miner version
- app: periodic weighted-random auto-balance of the pool while pool-mining (~30-min cadence; restarts the miner only when the pick actually changes), plus snapshot + refresh accessors for the UI. - app_network: resolve the xmrig algo per pool at start (pool.dragonx.cc = rx/dragonx, pool.dragonx.is = rx/hush; custom hosts keep the setting). - xmrig_manager: schema-aware pool-side hashrate readout (fixes a silent 0 for Miningcore pools); expose the running miner's version from its HTTP API and a cached `xmrig --version` detection so the UI can show it before mining. - wallet_state: carry the running miner's version. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
99
src/app.cpp
99
src/app.cpp
@@ -22,6 +22,7 @@
|
|||||||
#include "daemon/embedded_daemon.h"
|
#include "daemon/embedded_daemon.h"
|
||||||
#include "daemon/lifecycle_adapters.h"
|
#include "daemon/lifecycle_adapters.h"
|
||||||
#include "daemon/xmrig_manager.h"
|
#include "daemon/xmrig_manager.h"
|
||||||
|
#include "util/pool_registry.h"
|
||||||
#include "ui/windows/main_window.h"
|
#include "ui/windows/main_window.h"
|
||||||
#include "ui/windows/balance_tab.h"
|
#include "ui/windows/balance_tab.h"
|
||||||
#include "ui/windows/send_tab.h"
|
#include "ui/windows/send_tab.h"
|
||||||
@@ -109,9 +110,101 @@ namespace dragonx {
|
|||||||
|
|
||||||
using json = nlohmann::json;
|
using json = nlohmann::json;
|
||||||
|
|
||||||
App::App() = default;
|
App::App()
|
||||||
|
{
|
||||||
|
// Seed the auto-balance RNG once per run so weighted-random pool selection isn't
|
||||||
|
// deterministic across launches.
|
||||||
|
balance_rng_.seed(std::random_device{}());
|
||||||
|
}
|
||||||
App::~App() = default;
|
App::~App() = default;
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
// How often auto-balance re-evaluates the pool while active. Long, because switching
|
||||||
|
// restarts the miner (drops in-flight shares + reconnect); the incumbent stickiness
|
||||||
|
// in chooseWeightedPool makes actual switches rarer still.
|
||||||
|
constexpr long long kRebalanceIntervalMs = 30LL * 60LL * 1000LL; // 30 minutes
|
||||||
|
|
||||||
|
long long steadyNowMs()
|
||||||
|
{
|
||||||
|
using namespace std::chrono;
|
||||||
|
return duration_cast<milliseconds>(steady_clock::now().time_since_epoch()).count();
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
void App::updatePoolAutoBalance()
|
||||||
|
{
|
||||||
|
if (!settings_) return;
|
||||||
|
if (!supportsPoolMining()) return; // pool mining is full-node only
|
||||||
|
if (settings_->getPoolSelectMode() != config::Settings::PoolSelectMode::AutoBalance) return;
|
||||||
|
if (!settings_->getPoolMode()) return; // only while POOL mode is selected
|
||||||
|
|
||||||
|
const long long now = steadyNowMs();
|
||||||
|
const bool intervalDue = (last_balance_eval_ms_ == 0) ||
|
||||||
|
(now - last_balance_eval_ms_ >= kRebalanceIntervalMs);
|
||||||
|
|
||||||
|
// Kick a background refresh when requested or due (never while one is in flight).
|
||||||
|
if ((balance_refresh_pending_ || intervalDue) && !pool_stats_service_.busy()) {
|
||||||
|
balance_refresh_pending_ = false;
|
||||||
|
last_balance_eval_ms_ = now;
|
||||||
|
balance_snapshot_seen_ = false;
|
||||||
|
pool_stats_service_.refresh(util::knownPools());
|
||||||
|
return; // results land on a later frame
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply the freshly-completed snapshot exactly once.
|
||||||
|
if (!pool_stats_service_.busy()) {
|
||||||
|
const auto snap = pool_stats_service_.snapshot();
|
||||||
|
if (snap.ready && !balance_snapshot_seen_) {
|
||||||
|
balance_snapshot_seen_ = true;
|
||||||
|
applyPoolAutoBalance(snap);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void App::applyPoolAutoBalance(const util::PoolStatsService::Snapshot& snap)
|
||||||
|
{
|
||||||
|
const auto& pools = util::knownPools();
|
||||||
|
|
||||||
|
std::vector<util::PoolHashrate> samples;
|
||||||
|
samples.reserve(pools.size());
|
||||||
|
for (const auto& kp : pools) {
|
||||||
|
const auto it = snap.byId.find(kp.id);
|
||||||
|
samples.push_back(it != snap.byId.end()
|
||||||
|
? it->second
|
||||||
|
: util::PoolHashrate{kp.id, 0.0, false});
|
||||||
|
}
|
||||||
|
|
||||||
|
const util::KnownPool* current = util::findKnownPoolByUrl(settings_->getPoolUrl());
|
||||||
|
const std::string currentId = current ? current->id : std::string{};
|
||||||
|
|
||||||
|
const std::string chosenId = util::chooseWeightedPool(samples, currentId, balance_rng_);
|
||||||
|
if (chosenId.empty() || chosenId == currentId) return; // keep the current pool
|
||||||
|
|
||||||
|
const util::KnownPool* chosen = nullptr;
|
||||||
|
for (const auto& kp : pools)
|
||||||
|
if (kp.id == chosenId) { chosen = &kp; break; }
|
||||||
|
if (!chosen) return;
|
||||||
|
|
||||||
|
settings_->setPoolUrl(chosen->stratum);
|
||||||
|
settings_->save();
|
||||||
|
|
||||||
|
ui::Notifications::instance().info(
|
||||||
|
std::string(TR("mining_auto_balanced_to")) + " " + chosen->label);
|
||||||
|
|
||||||
|
// Restart so the new pool (and its per-pool algo) takes effect immediately.
|
||||||
|
if (xmrig_manager_ && xmrig_manager_->isRunning()) {
|
||||||
|
const int threads = xmrig_manager_->getRequestedThreads();
|
||||||
|
stopPoolMining();
|
||||||
|
startPoolMining(threads);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string App::poolMiningInstalledVersion()
|
||||||
|
{
|
||||||
|
daemon::XmrigManager::startVersionDetection(); // idempotent one-shot
|
||||||
|
return daemon::XmrigManager::installedVersion();
|
||||||
|
}
|
||||||
|
|
||||||
bool App::sendStopCommandSafely(rpc::RPCClient& client, const char* context)
|
bool App::sendStopCommandSafely(rpc::RPCClient& client, const char* context)
|
||||||
{
|
{
|
||||||
const char* label = context ? context : "App";
|
const char* label = context ? context : "App";
|
||||||
@@ -706,6 +799,7 @@ void App::update()
|
|||||||
ps.pool_diff = xs.pool_diff;
|
ps.pool_diff = xs.pool_diff;
|
||||||
ps.pool_url = xs.pool_url;
|
ps.pool_url = xs.pool_url;
|
||||||
ps.algo = xs.algo;
|
ps.algo = xs.algo;
|
||||||
|
ps.version = xs.version;
|
||||||
ps.connected = xs.connected;
|
ps.connected = xs.connected;
|
||||||
// Get memory directly from OS (more reliable than API)
|
// Get memory directly from OS (more reliable than API)
|
||||||
double memMB = xmrig_manager_->getMemoryUsageMB();
|
double memMB = xmrig_manager_->getMemoryUsageMB();
|
||||||
@@ -723,6 +817,9 @@ void App::update()
|
|||||||
state_.pool_mining.xmrig_running = false;
|
state_.pool_mining.xmrig_running = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Auto-balance: periodically re-pick the pool by hashrate (self-throttled).
|
||||||
|
updatePoolAutoBalance();
|
||||||
|
|
||||||
// Populate solo mining log lines from daemon output
|
// Populate solo mining log lines from daemon output
|
||||||
if (daemon_controller_ && daemon_controller_->isRunning()) {
|
if (daemon_controller_ && daemon_controller_->isRunning()) {
|
||||||
state_.mining.log_lines = daemon_controller_->recentLines(50);
|
state_.mining.log_lines = daemon_controller_->recentLines(50);
|
||||||
|
|||||||
24
src/app.h
24
src/app.h
@@ -19,6 +19,7 @@
|
|||||||
#include "services/wallet_security_controller.h"
|
#include "services/wallet_security_controller.h"
|
||||||
#include "services/wallet_security_workflow.h"
|
#include "services/wallet_security_workflow.h"
|
||||||
#include "util/async_task_manager.h"
|
#include "util/async_task_manager.h"
|
||||||
|
#include "util/pool_stats_service.h"
|
||||||
#include "wallet/wallet_capabilities.h"
|
#include "wallet/wallet_capabilities.h"
|
||||||
#include "ui/sidebar.h"
|
#include "ui/sidebar.h"
|
||||||
#include "ui/windows/console_tab.h"
|
#include "ui/windows/console_tab.h"
|
||||||
@@ -204,6 +205,17 @@ public:
|
|||||||
return xmrig_manager_ && xmrig_manager_->isRunning();
|
return xmrig_manager_ && xmrig_manager_->isRunning();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Auto-balance: latest per-pool hashrate snapshot (for the mining tab pool list),
|
||||||
|
// and a request to refresh it now (Refresh button / switching into Auto mode).
|
||||||
|
util::PoolStatsService::Snapshot poolStatsSnapshot() const {
|
||||||
|
return pool_stats_service_.snapshot();
|
||||||
|
}
|
||||||
|
void requestPoolBalanceRefresh() { balance_refresh_pending_ = true; }
|
||||||
|
|
||||||
|
// Installed miner version (detected from `xmrig --version`, cached; kicks the one-shot
|
||||||
|
// detection on first call) so the mining tab can show it before mining starts.
|
||||||
|
std::string poolMiningInstalledVersion();
|
||||||
|
|
||||||
// Mine-when-idle state query
|
// Mine-when-idle state query
|
||||||
bool isIdleMiningActive() const { return idle_mining_active_; }
|
bool isIdleMiningActive() const { return idle_mining_active_; }
|
||||||
|
|
||||||
@@ -455,6 +467,11 @@ private:
|
|||||||
void pruneShieldedHistoryScanProgress();
|
void pruneShieldedHistoryScanProgress();
|
||||||
void invalidateShieldedHistoryScanProgress(bool persistCache);
|
void invalidateShieldedHistoryScanProgress(bool persistCache);
|
||||||
|
|
||||||
|
// Auto-balance pool selection: drive the periodic hashrate refresh and apply a
|
||||||
|
// freshly-completed snapshot (weighted-random pick + optional miner restart).
|
||||||
|
void updatePoolAutoBalance();
|
||||||
|
void applyPoolAutoBalance(const util::PoolStatsService::Snapshot& snap);
|
||||||
|
|
||||||
// Subsystems
|
// Subsystems
|
||||||
std::unique_ptr<rpc::RPCClient> rpc_;
|
std::unique_ptr<rpc::RPCClient> rpc_;
|
||||||
std::unique_ptr<rpc::RPCWorker> worker_;
|
std::unique_ptr<rpc::RPCWorker> worker_;
|
||||||
@@ -488,6 +505,13 @@ private:
|
|||||||
bool lite_startup_lock_checked_ = false;
|
bool lite_startup_lock_checked_ = false;
|
||||||
std::unique_ptr<daemon::DaemonController> daemon_controller_;
|
std::unique_ptr<daemon::DaemonController> daemon_controller_;
|
||||||
std::unique_ptr<daemon::XmrigManager> xmrig_manager_;
|
std::unique_ptr<daemon::XmrigManager> xmrig_manager_;
|
||||||
|
// Auto-balance runtime state (pool mining, full-node only). The service fetches
|
||||||
|
// pool hashrates off-thread; the RNG drives the weighted-random pick.
|
||||||
|
util::PoolStatsService pool_stats_service_;
|
||||||
|
std::mt19937 balance_rng_;
|
||||||
|
long long last_balance_eval_ms_ = 0; // steady-clock ms of the last refresh kick
|
||||||
|
bool balance_refresh_pending_ = false; // UI asked for an immediate refresh
|
||||||
|
bool balance_snapshot_seen_ = false; // the current in-flight snapshot was applied
|
||||||
util::AsyncTaskManager async_tasks_;
|
util::AsyncTaskManager async_tasks_;
|
||||||
bool pending_antivirus_dialog_ = false; // Show Windows Defender help dialog
|
bool pending_antivirus_dialog_ = false; // Show Windows Defender help dialog
|
||||||
|
|
||||||
|
|||||||
@@ -38,6 +38,7 @@
|
|||||||
#include "daemon/daemon_controller.h"
|
#include "daemon/daemon_controller.h"
|
||||||
#include "daemon/embedded_daemon.h"
|
#include "daemon/embedded_daemon.h"
|
||||||
#include "daemon/xmrig_manager.h"
|
#include "daemon/xmrig_manager.h"
|
||||||
|
#include "util/pool_registry.h"
|
||||||
#include "ui/notifications.h"
|
#include "ui/notifications.h"
|
||||||
#include "default_banlist_embedded.h"
|
#include "default_banlist_embedded.h"
|
||||||
#include "util/amount_format.h"
|
#include "util/amount_format.h"
|
||||||
@@ -1718,7 +1719,9 @@ void App::startPoolMining(int threads)
|
|||||||
daemon::XmrigManager::Config cfg;
|
daemon::XmrigManager::Config cfg;
|
||||||
cfg.pool_url = settings_->getPoolUrl();
|
cfg.pool_url = settings_->getPoolUrl();
|
||||||
cfg.worker_name = settings_->getPoolWorker();
|
cfg.worker_name = settings_->getPoolWorker();
|
||||||
cfg.algo = settings_->getPoolAlgo();
|
// The algo follows the pool: official pools use their own algo (pool.dragonx.cc
|
||||||
|
// needs rx/dragonx, pool.dragonx.is rx/hush); custom hosts keep the setting.
|
||||||
|
cfg.algo = util::resolvePoolAlgo(cfg.pool_url, settings_->getPoolAlgo());
|
||||||
cfg.threads = threads; // Use the same thread selection as solo mining
|
cfg.threads = threads; // Use the same thread selection as solo mining
|
||||||
cfg.tls = settings_->getPoolTls();
|
cfg.tls = settings_->getPoolTls();
|
||||||
cfg.hugepages = settings_->getPoolHugepages();
|
cfg.hugepages = settings_->getPoolHugepages();
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
#include "xmrig_manager.h"
|
#include "xmrig_manager.h"
|
||||||
#include "../resources/embedded_resources.h"
|
#include "../resources/embedded_resources.h"
|
||||||
|
|
||||||
|
#include <cctype>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
@@ -22,6 +23,7 @@
|
|||||||
#include <curl/curl.h>
|
#include <curl/curl.h>
|
||||||
|
|
||||||
#include "../util/logger.h"
|
#include "../util/logger.h"
|
||||||
|
#include "../util/pool_registry.h"
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#include <winsock2.h>
|
#include <winsock2.h>
|
||||||
@@ -718,6 +720,11 @@ void XmrigManager::fetchStatsHttp() {
|
|||||||
|
|
||||||
std::lock_guard<std::mutex> lk(stats_mutex_);
|
std::lock_guard<std::mutex> lk(stats_mutex_);
|
||||||
|
|
||||||
|
// Miner version (top-level in /2/summary) — lets the UI show the actually
|
||||||
|
// running miner's version even when no release tag was persisted (bundled miner).
|
||||||
|
if (resp.contains("version") && resp["version"].is_string())
|
||||||
|
stats_.version = resp["version"].get<std::string>();
|
||||||
|
|
||||||
if (resp.contains("hashrate") && resp["hashrate"].contains("total")) {
|
if (resp.contains("hashrate") && resp["hashrate"].contains("total")) {
|
||||||
auto& total = resp["hashrate"]["total"];
|
auto& total = resp["hashrate"]["total"];
|
||||||
if (total.is_array() && total.size() >= 3) {
|
if (total.is_array() && total.size() >= 3) {
|
||||||
@@ -768,10 +775,14 @@ void XmrigManager::fetchStatsHttp() {
|
|||||||
void XmrigManager::fetchPoolApiStats() {
|
void XmrigManager::fetchPoolApiStats() {
|
||||||
if (state_ != State::Running || pool_host_.empty()) return;
|
if (state_ != State::Running || pool_host_.empty()) return;
|
||||||
|
|
||||||
// Query the pool's public stats API
|
// Resolve the stats endpoint + JSON schema for this pool. Known pools carry their
|
||||||
std::string url = "https://" + pool_host_ + "/api/stats";
|
// own API shape (pool.dragonx.is = custom /api/stats; pool.dragonx.cc = Miningcore
|
||||||
std::string responseData;
|
// /api/pools); unknown/custom hosts fall back to the .is convention.
|
||||||
|
const util::KnownPool* known = util::findKnownPoolByUrl(pool_host_);
|
||||||
|
const std::string url = known ? known->statsUrl
|
||||||
|
: ("https://" + pool_host_ + "/api/stats");
|
||||||
|
|
||||||
|
std::string responseData;
|
||||||
CURL* curl = curl_easy_init();
|
CURL* curl = curl_easy_init();
|
||||||
if (!curl) return;
|
if (!curl) return;
|
||||||
|
|
||||||
@@ -782,31 +793,99 @@ void XmrigManager::fetchPoolApiStats() {
|
|||||||
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT_MS, 3000L);
|
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT_MS, 3000L);
|
||||||
curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1L);
|
curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1L);
|
||||||
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
|
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
|
||||||
|
// pool.dragonx.cc sits behind Cloudflare and 403s odd User-Agents.
|
||||||
|
curl_easy_setopt(curl, CURLOPT_USERAGENT, "Mozilla/5.0 (compatible; ObsidianDragon)");
|
||||||
|
curl_easy_setopt(curl, CURLOPT_ACCEPT_ENCODING, "");
|
||||||
|
|
||||||
CURLcode res = curl_easy_perform(curl);
|
CURLcode res = curl_easy_perform(curl);
|
||||||
curl_easy_cleanup(curl);
|
curl_easy_cleanup(curl);
|
||||||
|
|
||||||
if (res != CURLE_OK) return;
|
if (res != CURLE_OK) return;
|
||||||
|
|
||||||
try {
|
bool ok = false;
|
||||||
json resp = json::parse(responseData);
|
const double poolHR = util::parsePoolHashrate(
|
||||||
|
known ? known->schema : util::PoolStatsSchema::DragonXIs,
|
||||||
// Pool stats API format: { "pools": { "<name>": { "hashrate": ... } } }
|
responseData, known ? known->miningcorePoolId : std::string{}, ok);
|
||||||
double poolHR = 0;
|
if (!ok) return;
|
||||||
if (resp.contains("pools") && resp["pools"].is_object()) {
|
|
||||||
for (auto& [key, pool] : resp["pools"].items()) {
|
|
||||||
if (pool.contains("hashrate") && pool["hashrate"].is_number()) {
|
|
||||||
poolHR = pool["hashrate"].get<double>();
|
|
||||||
break; // Use the first pool entry
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lk(stats_mutex_);
|
std::lock_guard<std::mutex> lk(stats_mutex_);
|
||||||
stats_.pool_hashrate = poolHR;
|
stats_.pool_hashrate = poolHR;
|
||||||
} catch (...) {
|
|
||||||
// Malformed response — ignore
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Installed-miner version detection (`<binary> --version`, cached)
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
std::mutex g_installed_ver_mutex;
|
||||||
|
std::string g_installed_ver;
|
||||||
|
std::atomic<bool> g_ver_detect_started{false};
|
||||||
|
|
||||||
|
// Extract the first "D.D[.D...]" version token from `--version` output (skips the
|
||||||
|
// build date, which uses '-' separators). Returns e.g. "6.21.0", or "" if none.
|
||||||
|
std::string parseMinerVersion(const std::string& out)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < out.size(); ++i) {
|
||||||
|
if (std::isdigit(static_cast<unsigned char>(out[i]))) {
|
||||||
|
size_t j = i;
|
||||||
|
int dots = 0;
|
||||||
|
while (j < out.size() &&
|
||||||
|
(std::isdigit(static_cast<unsigned char>(out[j])) || out[j] == '.')) {
|
||||||
|
if (out[j] == '.') ++dots;
|
||||||
|
++j;
|
||||||
|
}
|
||||||
|
if (dots >= 1 && (j - i) >= 3) {
|
||||||
|
// Include a trailing build suffix like "-hac" / "-drg1" (e.g. "6.25.1-hac"),
|
||||||
|
// matching what the running miner's API reports.
|
||||||
|
size_t end = j;
|
||||||
|
if (end < out.size() && out[end] == '-') {
|
||||||
|
size_t k = end + 1;
|
||||||
|
while (k < out.size() && std::isalnum(static_cast<unsigned char>(out[k]))) ++k;
|
||||||
|
if (k > end + 1) end = k;
|
||||||
|
}
|
||||||
|
return out.substr(i, end - i);
|
||||||
|
}
|
||||||
|
i = j;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
void XmrigManager::startVersionDetection()
|
||||||
|
{
|
||||||
|
if (g_ver_detect_started.exchange(true)) return; // one-shot
|
||||||
|
std::thread([]() {
|
||||||
|
const std::string bin = findXmrigBinary();
|
||||||
|
std::string ver;
|
||||||
|
if (!bin.empty()) {
|
||||||
|
const std::string cmd = "\"" + bin + "\" --version 2>&1";
|
||||||
|
#ifdef _WIN32
|
||||||
|
FILE* fp = _popen(cmd.c_str(), "r");
|
||||||
|
#else
|
||||||
|
FILE* fp = popen(cmd.c_str(), "r");
|
||||||
|
#endif
|
||||||
|
if (fp) {
|
||||||
|
std::string out;
|
||||||
|
char buf[256];
|
||||||
|
size_t n;
|
||||||
|
while ((n = fread(buf, 1, sizeof(buf), fp)) > 0) out.append(buf, n);
|
||||||
|
#ifdef _WIN32
|
||||||
|
_pclose(fp);
|
||||||
|
#else
|
||||||
|
pclose(fp);
|
||||||
|
#endif
|
||||||
|
ver = parseMinerVersion(out);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
std::lock_guard<std::mutex> lk(g_installed_ver_mutex);
|
||||||
|
g_installed_ver = ver;
|
||||||
|
}).detach();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string XmrigManager::installedVersion()
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lk(g_installed_ver_mutex);
|
||||||
|
return g_installed_ver;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace daemon
|
} // namespace daemon
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ public:
|
|||||||
double pool_diff = 0;
|
double pool_diff = 0;
|
||||||
std::string pool_url;
|
std::string pool_url;
|
||||||
std::string algo;
|
std::string algo;
|
||||||
|
std::string version; // miner version reported by the running xmrig API
|
||||||
bool connected = false;
|
bool connected = false;
|
||||||
// Memory usage
|
// Memory usage
|
||||||
int64_t memory_free = 0; // bytes
|
int64_t memory_free = 0; // bytes
|
||||||
@@ -137,6 +138,18 @@ public:
|
|||||||
*/
|
*/
|
||||||
static std::string findXmrigBinary();
|
static std::string findXmrigBinary();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Kick a one-shot background `<binary> --version` detection (idempotent).
|
||||||
|
* Lets the UI show the installed miner's version before mining is ever started.
|
||||||
|
*/
|
||||||
|
static void startVersionDetection();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Cached installed-miner version parsed by startVersionDetection().
|
||||||
|
* Empty until detection completes (or if no binary/parse failed). Thread-safe.
|
||||||
|
*/
|
||||||
|
static std::string installedVersion();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool generateConfig(const Config& cfg, const std::string& outPath);
|
bool generateConfig(const Config& cfg, const std::string& outPath);
|
||||||
bool startProcess(const std::string& xmrigPath, const std::string& cfgPath, int threads);
|
bool startProcess(const std::string& xmrigPath, const std::string& cfgPath, int threads);
|
||||||
|
|||||||
@@ -170,6 +170,7 @@ struct PoolMiningState {
|
|||||||
bool xmrig_running = false;
|
bool xmrig_running = false;
|
||||||
std::string pool_url;
|
std::string pool_url;
|
||||||
std::string algo;
|
std::string algo;
|
||||||
|
std::string version; // running miner's version (from its API)
|
||||||
|
|
||||||
double hashrate_10s = 0;
|
double hashrate_10s = 0;
|
||||||
double hashrate_60s = 0;
|
double hashrate_60s = 0;
|
||||||
|
|||||||
Reference in New Issue
Block a user