refactor(mining): surface inconclusive benchmark; dedup idle combo
- 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) <noreply@anthropic.com>
This commit is contained in:
@@ -189,6 +189,11 @@ ThreadBenchmarkUpdate AdvanceThreadBenchmark(ThreadBenchmark& benchmark,
|
|||||||
update.startPoolMining = true;
|
update.startPoolMining = true;
|
||||||
update.startThreads = benchmark.optimal_threads;
|
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;
|
break;
|
||||||
|
|||||||
@@ -56,6 +56,7 @@ struct ThreadBenchmarkUpdate {
|
|||||||
int startThreads = 0;
|
int startThreads = 0;
|
||||||
bool saveOptimalThreads = false;
|
bool saveOptimalThreads = false;
|
||||||
int optimalThreads = 0;
|
int optimalThreads = 0;
|
||||||
|
bool inconclusive = false; // finished with no nonzero hashrate sample — caller should warn
|
||||||
};
|
};
|
||||||
|
|
||||||
ThreadBenchmarkUpdate AdvanceThreadBenchmark(ThreadBenchmark& benchmark,
|
ThreadBenchmarkUpdate AdvanceThreadBenchmark(ThreadBenchmark& benchmark,
|
||||||
|
|||||||
@@ -176,8 +176,9 @@ void RenderMiningControls(App* app, const WalletState& state, const MiningInfo&
|
|||||||
idleRightEdge = gBtnX - 4.0f * dp;
|
idleRightEdge = gBtnX - 4.0f * dp;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Idle delay combo (to the left, when idle is enabled and NOT in thread scaling mode)
|
// Idle delay combo renderer (shared by the non-scaling and thread-scaling
|
||||||
if (idleOn && !threadScaling) {
|
// branches below). Draws right-aligned at idleRightEdge and advances it.
|
||||||
|
auto renderIdleDelayCombo = [&](const char* comboId) {
|
||||||
struct DelayOption { int seconds; const char* label; };
|
struct DelayOption { int seconds; const char* label; };
|
||||||
static const DelayOption delays[] = {
|
static const DelayOption delays[] = {
|
||||||
{30, "30s"}, {60, "1m"}, {120, "2m"}, {300, "5m"}, {600, "10m"}
|
{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;
|
float comboY = curY + (headerH - ImGui::GetFrameHeight()) * 0.5f;
|
||||||
ImGui::SetCursorScreenPos(ImVec2(comboX, comboY));
|
ImGui::SetCursorScreenPos(ImVec2(comboX, comboY));
|
||||||
ImGui::SetNextItemWidth(comboW);
|
ImGui::SetNextItemWidth(comboW);
|
||||||
if (ImGui::BeginCombo("##IdleDelay", previewLabel, ImGuiComboFlags_NoArrowButton)) {
|
if (ImGui::BeginCombo(comboId, previewLabel, ImGuiComboFlags_NoArrowButton)) {
|
||||||
for (const auto& d : delays) {
|
for (const auto& d : delays) {
|
||||||
bool selected = (d.seconds == curDelay);
|
bool selected = (d.seconds == curDelay);
|
||||||
if (ImGui::Selectable(d.label, selected)) {
|
if (ImGui::Selectable(d.label, selected)) {
|
||||||
@@ -206,6 +207,11 @@ void RenderMiningControls(App* app, const WalletState& state, const MiningInfo&
|
|||||||
if (ImGui::IsItemHovered())
|
if (ImGui::IsItemHovered())
|
||||||
material::Tooltip("%s", TR("tt_idle_delay"));
|
material::Tooltip("%s", TR("tt_idle_delay"));
|
||||||
idleRightEdge = comboX - 4.0f * dp;
|
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
|
// 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());
|
int hwThreads = std::max(1, (int)std::thread::hardware_concurrency());
|
||||||
|
|
||||||
// Idle delay combo
|
// Idle delay combo
|
||||||
{
|
renderIdleDelayCombo("##IdleDelayScale");
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Idle threads combo (threads when system is idle)
|
// Idle threads combo (threads when system is idle)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -248,6 +248,11 @@ static void RenderMiningTabContent(App* app)
|
|||||||
if (benchmarkUpdate.startPoolMining) {
|
if (benchmarkUpdate.startPoolMining) {
|
||||||
app->startPoolMining(benchmarkUpdate.startThreads);
|
app->startPoolMining(benchmarkUpdate.startThreads);
|
||||||
}
|
}
|
||||||
|
if (benchmarkUpdate.inconclusive) {
|
||||||
|
Notifications::instance().warning(
|
||||||
|
"Benchmark inconclusive: no hashrate samples were recorded. "
|
||||||
|
"Check the pool connection and try again.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ================================================================
|
// ================================================================
|
||||||
|
|||||||
@@ -25,7 +25,6 @@ static char s_address[512] = "";
|
|||||||
static double s_amount = 0.0;
|
static double s_amount = 0.0;
|
||||||
static char s_memo[512] = "";
|
static char s_memo[512] = "";
|
||||||
static char s_label[128] = "";
|
static char s_label[128] = "";
|
||||||
static int s_selected_addr_idx = -1;
|
|
||||||
static std::string s_payment_uri;
|
static std::string s_payment_uri;
|
||||||
static uintptr_t s_qr_texture = 0;
|
static uintptr_t s_qr_texture = 0;
|
||||||
static int s_qr_width = 0;
|
static int s_qr_width = 0;
|
||||||
@@ -45,7 +44,6 @@ void RequestPaymentDialog::show(const std::string& address)
|
|||||||
s_amount = 0.0;
|
s_amount = 0.0;
|
||||||
s_memo[0] = '\0';
|
s_memo[0] = '\0';
|
||||||
s_label[0] = '\0';
|
s_label[0] = '\0';
|
||||||
s_selected_addr_idx = -1;
|
|
||||||
s_uri_dirty = true;
|
s_uri_dirty = true;
|
||||||
|
|
||||||
if (!address.empty()) {
|
if (!address.empty()) {
|
||||||
@@ -107,7 +105,7 @@ void RequestPaymentDialog::render(App* app)
|
|||||||
label = label.substr(0, zAddrFrontLbl.truncate) + "..." + label.substr(label.length() - zAddrBackLbl.truncate);
|
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);
|
strncpy(s_address, addr.address.c_str(), sizeof(s_address) - 1);
|
||||||
s_uri_dirty = true;
|
s_uri_dirty = true;
|
||||||
}
|
}
|
||||||
@@ -124,7 +122,7 @@ void RequestPaymentDialog::render(App* app)
|
|||||||
label = label.substr(0, tAddrFrontLbl.truncate) + "..." + label.substr(label.length() - tAddrBackLbl.truncate);
|
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);
|
strncpy(s_address, addr.address.c_str(), sizeof(s_address) - 1);
|
||||||
s_uri_dirty = true;
|
s_uri_dirty = true;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user