From ec485388817cf84dac5fb2d5cf7300c1690f3c64 Mon Sep 17 00:00:00 2001 From: DanS Date: Sun, 5 Jul 2026 15:09:08 -0500 Subject: [PATCH] refactor(mining): surface inconclusive benchmark; dedup idle combo MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - mining_benchmark: when a thread benchmark finishes with no nonzero hashrate sample (e.g. the pool never reported a rate), don't finish silently — set a new `inconclusive` flag on ThreadBenchmarkUpdate and let mining_tab warn. Keeps the state-machine core pure/no-I/O (it is unit-tested), rather than calling the Notifications singleton from it. - mining_controls: fold the two byte-identical idle-delay combo blocks (non-scaling + thread-scaling branches) into one lambda parameterised by combo id; removes ~30 lines of duplication. - request_payment: drop the dead s_selected_addr_idx state and write the address-selected comparisons as std::string == char* consistently. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/ui/windows/mining_benchmark.cpp | 5 +++ src/ui/windows/mining_benchmark.h | 1 + src/ui/windows/mining_controls.cpp | 43 ++++++----------------- src/ui/windows/mining_tab.cpp | 5 +++ src/ui/windows/request_payment_dialog.cpp | 8 ++--- 5 files changed, 24 insertions(+), 38 deletions(-) diff --git a/src/ui/windows/mining_benchmark.cpp b/src/ui/windows/mining_benchmark.cpp index 2a2762d..618a697 100644 --- a/src/ui/windows/mining_benchmark.cpp +++ b/src/ui/windows/mining_benchmark.cpp @@ -189,6 +189,11 @@ ThreadBenchmarkUpdate AdvanceThreadBenchmark(ThreadBenchmark& benchmark, update.startPoolMining = true; update.startThreads = benchmark.optimal_threads; } + } else { + // No candidate produced a nonzero hashrate (e.g. a pool that never + // reported a rate). Don't finish silently — flag the run as + // inconclusive so the caller can surface it (keeps this core pure). + update.inconclusive = true; } } break; diff --git a/src/ui/windows/mining_benchmark.h b/src/ui/windows/mining_benchmark.h index 2518034..b28ba31 100644 --- a/src/ui/windows/mining_benchmark.h +++ b/src/ui/windows/mining_benchmark.h @@ -56,6 +56,7 @@ struct ThreadBenchmarkUpdate { int startThreads = 0; bool saveOptimalThreads = false; int optimalThreads = 0; + bool inconclusive = false; // finished with no nonzero hashrate sample — caller should warn }; ThreadBenchmarkUpdate AdvanceThreadBenchmark(ThreadBenchmark& benchmark, diff --git a/src/ui/windows/mining_controls.cpp b/src/ui/windows/mining_controls.cpp index 9526d03..009fd02 100644 --- a/src/ui/windows/mining_controls.cpp +++ b/src/ui/windows/mining_controls.cpp @@ -176,8 +176,9 @@ void RenderMiningControls(App* app, const WalletState& state, const MiningInfo& idleRightEdge = gBtnX - 4.0f * dp; } - // Idle delay combo (to the left, when idle is enabled and NOT in thread scaling mode) - if (idleOn && !threadScaling) { + // Idle delay combo renderer (shared by the non-scaling and thread-scaling + // branches below). Draws right-aligned at idleRightEdge and advances it. + auto renderIdleDelayCombo = [&](const char* comboId) { struct DelayOption { int seconds; const char* label; }; static const DelayOption delays[] = { {30, "30s"}, {60, "1m"}, {120, "2m"}, {300, "5m"}, {600, "10m"} @@ -192,7 +193,7 @@ void RenderMiningControls(App* app, const WalletState& state, const MiningInfo& float comboY = curY + (headerH - ImGui::GetFrameHeight()) * 0.5f; ImGui::SetCursorScreenPos(ImVec2(comboX, comboY)); ImGui::SetNextItemWidth(comboW); - if (ImGui::BeginCombo("##IdleDelay", previewLabel, ImGuiComboFlags_NoArrowButton)) { + if (ImGui::BeginCombo(comboId, previewLabel, ImGuiComboFlags_NoArrowButton)) { for (const auto& d : delays) { bool selected = (d.seconds == curDelay); if (ImGui::Selectable(d.label, selected)) { @@ -206,6 +207,11 @@ void RenderMiningControls(App* app, const WalletState& state, const MiningInfo& if (ImGui::IsItemHovered()) material::Tooltip("%s", TR("tt_idle_delay")); idleRightEdge = comboX - 4.0f * dp; + }; + + // Idle delay combo (to the left, when idle is enabled and NOT in thread scaling mode) + if (idleOn && !threadScaling) { + renderIdleDelayCombo("##IdleDelay"); } // Thread scaling controls: idle delay + active threads / idle threads combos @@ -213,36 +219,7 @@ void RenderMiningControls(App* app, const WalletState& state, const MiningInfo& int hwThreads = std::max(1, (int)std::thread::hardware_concurrency()); // Idle delay combo - { - struct DelayOption { int seconds; const char* label; }; - static const DelayOption delays[] = { - {30, "30s"}, {60, "1m"}, {120, "2m"}, {300, "5m"}, {600, "10m"} - }; - int curDelay = app->settings()->getMineIdleDelay(); - const char* previewLabel = "2m"; - for (const auto& d : delays) { - if (d.seconds == curDelay) { previewLabel = d.label; break; } - } - float comboW = schema::UI().drawElement("components.settings-page", "idle-combo-width").sizeOr(64.0f); - float comboX = idleRightEdge - comboW; - float comboY = curY + (headerH - ImGui::GetFrameHeight()) * 0.5f; - ImGui::SetCursorScreenPos(ImVec2(comboX, comboY)); - ImGui::SetNextItemWidth(comboW); - if (ImGui::BeginCombo("##IdleDelayScale", previewLabel, ImGuiComboFlags_NoArrowButton)) { - for (const auto& d : delays) { - bool selected = (d.seconds == curDelay); - if (ImGui::Selectable(d.label, selected)) { - app->settings()->setMineIdleDelay(d.seconds); - app->settings()->save(); - } - if (selected) ImGui::SetItemDefaultFocus(); - } - ImGui::EndCombo(); - } - if (ImGui::IsItemHovered()) - material::Tooltip("%s", TR("tt_idle_delay")); - idleRightEdge = comboX - 4.0f * dp; - } + renderIdleDelayCombo("##IdleDelayScale"); // Idle threads combo (threads when system is idle) { diff --git a/src/ui/windows/mining_tab.cpp b/src/ui/windows/mining_tab.cpp index b7296bc..6e86d56 100644 --- a/src/ui/windows/mining_tab.cpp +++ b/src/ui/windows/mining_tab.cpp @@ -248,6 +248,11 @@ static void RenderMiningTabContent(App* app) if (benchmarkUpdate.startPoolMining) { app->startPoolMining(benchmarkUpdate.startThreads); } + if (benchmarkUpdate.inconclusive) { + Notifications::instance().warning( + "Benchmark inconclusive: no hashrate samples were recorded. " + "Check the pool connection and try again."); + } } // ================================================================ diff --git a/src/ui/windows/request_payment_dialog.cpp b/src/ui/windows/request_payment_dialog.cpp index 557a9fd..3b82cd9 100644 --- a/src/ui/windows/request_payment_dialog.cpp +++ b/src/ui/windows/request_payment_dialog.cpp @@ -25,7 +25,6 @@ static char s_address[512] = ""; static double s_amount = 0.0; static char s_memo[512] = ""; static char s_label[128] = ""; -static int s_selected_addr_idx = -1; static std::string s_payment_uri; static uintptr_t s_qr_texture = 0; static int s_qr_width = 0; @@ -45,7 +44,6 @@ void RequestPaymentDialog::show(const std::string& address) s_amount = 0.0; s_memo[0] = '\0'; s_label[0] = '\0'; - s_selected_addr_idx = -1; s_uri_dirty = true; if (!address.empty()) { @@ -107,13 +105,13 @@ void RequestPaymentDialog::render(App* app) label = label.substr(0, zAddrFrontLbl.truncate) + "..." + label.substr(label.length() - zAddrBackLbl.truncate); } - if (ImGui::Selectable(label.c_str(), s_address == addr.address)) { + if (ImGui::Selectable(label.c_str(), addr.address == s_address)) { strncpy(s_address, addr.address.c_str(), sizeof(s_address) - 1); s_uri_dirty = true; } } } - + // T-addresses if (!state.t_addresses.empty()) { ImGui::TextDisabled("%s", TR("request_transparent_addrs")); @@ -124,7 +122,7 @@ void RequestPaymentDialog::render(App* app) label = label.substr(0, tAddrFrontLbl.truncate) + "..." + label.substr(label.length() - tAddrBackLbl.truncate); } - if (ImGui::Selectable(label.c_str(), s_address == addr.address)) { + if (ImGui::Selectable(label.c_str(), addr.address == s_address)) { strncpy(s_address, addr.address.c_str(), sizeof(s_address) - 1); s_uri_dirty = true; }