- A mining start/stop/pool failure now sets a persistent App::mining_last_error_
(cleared on the next attempt), rendered as a red caption with "Press Mine to
try again" below the Mine button (plus a Dismiss, and a Windows-Defender
"How to fix" on an AV block), so a crashed/blocked/failed miner is no longer
just a button that "did nothing" once its toast faded. Two more hardcoded
English strings (pool-payout-invalid, AV-blocked) moved to i18n.
- Pool connection status is now a persistent "Status" row in the pool stats
card (PoolMiningState.running_since / last_error): it flips from "Connecting…"
to "Can't reach pool — check the URL" after a 30s timeout instead of sitting
on red forever, and no longer vanishes once logs arrive. The old transient
banner in mining_tab.cpp was removed.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Warmup/daemon status no longer appends a hardcoded English " (Block N)" — it
uses a translated warmup_block_fmt key.
- Recent-transaction type labels (Sent/Received/Mined) are now translated in the
UI consumer (recentTypeLabel in balance_recent_tx.cpp) with a generic
"Transaction" fallback, instead of the data layer's raw English getTypeDisplay().
- Mining: a disconnected solo miner hovering the dead Mine button now gets a
"not connected to the node" tooltip instead of a misleading "Start Mining"
(the tooltip chain had no branch for the solo !isConnected() disable).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
New-user mining cluster from the UX audit:
- Solo/Pool toggle: hover tooltips on each half explaining the trade-off
(solo = no fees but long waits on a small CPU; pool = frequent small payouts,
needs the miner + a shielded payout address).
- Payout field: when it's empty (new wallets have no z-address, and a pool
payout must be shielded) the bookmark button is replaced by a one-click
"Generate a shielded payout address" button (createNewZAddress → fills the
field, persists, toasts), instead of only a hover hint to the Receive tab.
- Miner updater pill: when no miner is installed it becomes a prominent accent
"Download miner" call-to-action with a "pool mining needs DRG-XMRig" tooltip,
instead of a subtle grey "Update" pill that's easy to miss.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The thread grid is inert during a benchmark, but the -/+ buttons and the
count field still took input: a click changed the shown and saved count
while the benchmark owned the miner's (before the previous commit it
also restarted xmrig at that count and spoiled the measurement). The
buttons and the field are now disabled until the benchmark ends.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Every thread-count change on the Mining tab saved settings.json and,
with a miner running, stopped and restarted it: xmrig re-inits its
RandomX dataset and reconnects to the pool, seconds of lost hashing
each time. A drag across the grid did this once per tile crossed (up to
~24), with a "Starting pool miner" toast each; every -/+ click or Enter
did it again.
The tab now hands each pick to the App, which puts the newest in
settings at once and applies it when the input settles: on drag
release, or 0.5 s after the last click, even if the Mining tab was left
in the meantime. The header, RAM estimate and tile fill still follow
the drag live.
- Pool: the restart is decided on the mining-control thread, after every
earlier start or stop has run. It never starts a miner the user
stopped, is a no-op when xmrig already runs at that count, and is no
longer silently skipped when the pick lands in another restart's stop
window (which left xmrig on the old count).
- Solo: one setgenerate per gesture. A pick made while one is in flight
now waits for it instead of being dropped (another stale count).
- Clicking the tile that is already selected does nothing; it used to
save settings and restart the miner.
- With idle thread scaling on, the grid no longer snaps back to the old
count while a pick is on its way to the miner. A pool auto-balance
restart keeps a count still queued.
- Idle thread scaling changes the pool count through the same retarget.
Its correction after a start compares with the count last requested,
not the xmrig API's lagging report, so it comes about 1 s in instead
of after the first API report (3-5 s).
- A retarget whose pool config no longer validates shows the same error
and stops the miner, as the old stop-then-start did.
- While a benchmark runs a pick is saved, but the miner change is
dropped: the benchmark owns the count until it ends.
A crash within 0.5 s of a pick, or mid-drag, loses that pick; every
clean exit saves it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
DragonX is a private chain (-ac_private=1): consensus rejects any
non-coinbase output to a transparent address, so a t-address can only
ever receive mining rewards, and its coins can only move to a shielded
address. The wallet treated them like ordinary recipients.
Block paying one:
- Send: a transparent recipient shows "Mining address - can't be paid"
and disables Review Send (tooltip explains; ask for a zs... address).
Typing, paste, contacts and payment URIs all go through this field.
- Overview drag-to-transfer: a mining-address row is never a transfer
target (it only reorders).
- Pool payout must be shielded (pools pay with ordinary transactions):
field tooltip, disabled Start button and the start check say why.
- isValidRecipientAddress() is now shielded-only; new isDragonXAddress()
and classifyRecipient() (Shielded / MiningOnly / Invalid).
Call them mining addresses:
- Overview: "Mining rewards" card (amber "Not yet shielded" when there
is a balance; hover explains; click opens the Shield dialog), "New
mining address" button with a tooltip, rows typed "Mining".
- QR / label dialogs, portfolio filter, contact badge ("Mining only"),
Receive notifications.
i18n: 17 new keys in all 8 languages, 12 dead keys removed, CJK subset
rebuilt. Tests: recipient classification, translation completeness.
UI sweep: new "send-mining-recipient" target.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Bundles the session's UI work (the touched files carry several of these
changes together, so they are committed as one coherent UI batch):
- FAQ: new RenderFaqDialog + data-driven faq_content, opened from a
status-bar "?" (and the Windows title bar), styled like the Wallets
modal with search, Wallet/Daemon tabs, and smooth scroll.
- DPI/font-scale audit: multiply hand-drawn absolute geometry by
Layout::dpiScale() across ~30 files so nothing renders native-size at
HiDPI / font_scale 1.5 (verified with a full sweep at 1.5x).
- Mining: chart now fills the horizontal space; thread stepper +/- buttons
match the input-box height; move the stratum-host toggle into
Node & Security (v1.3.0+).
- Settings: fix the auto-shield status text overlapping the grid.
- Sidebar: drop the peer-count badge on the Network button.
- i18n: wrap 193 hardcoded literals with TR() (keys/translations added in
the preceding i18n commit), so the security/PIN/lock flow, seed-backup
wizard, and witness-rebuild dialog localize.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The tail of the DPI/font-scale/responsiveness audit — ~26 remaining findings.
Container / recent-list (Theme-1 leftovers):
- Send: drop NoScrollbar|NoScrollWithMouse on ##SendFormScroll so Recent Sends is
reachable at font_scale 1.5 (parity with receive).
- Receive: cap the QR/form card via std::min(mainCardTargetH, availH - recentReserve)
so RECENT RECEIVED stays on-screen (identity at 1.0x).
- Wallets dialog: size the capped-mode list to whole rows so it no longer clips a
partial row / crowds "Create a new wallet".
Narrow-width (1024px) reflow:
- Console toolbar reserves space for ALL trailing controls (both icon toggles + zoom
buttons) so the +/- zoom no longer runs off-window.
- History sort combo sized to its measured widest localized label ("Newest first").
- Settings Theme/Layout/Language row: scale the wide→stacked breakpoint by dpiScale so
it drops to full-width stacked combos at 1.5x (Consolidated Card no longer clips).
- Recent-tx type label: derive the address column X from the measured label width so it
can't collide at narrow widths.
- Mining Recent Pool Payouts: floor the panel height to fit the empty-state caption.
Cosmetic ×dpiScale() on absolute geometry (no-ops at 1.0x): mining SOLO|POOL toggle &
idle combos, market pair-chips, password/PIN strength bars, receive/send currency
toggles, explorer search bar/rows/rounding, About-card logo, chat empty-state wrap,
recent-list address/time offsets, address-toolbar & two-row action buttons, console
line-gap/status-dot/pane rounding.
Verified at font_scale 1.5 and at 1024px across full-node + Lite + Windows (ctest
green) and an adversarial diff review (one over-reserve regression fixed).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Mining-tab UI improvements:
- Thread selector: a centered [-] N [+] stepper (top-aligned in the header) to pick an exact
thread count — number centered, -/+ step by one (clamped to [1, cores]), still typeable
(commits on Enter so it doesn't restart the miner mid-typing).
- Thread tiles now render at an adaptive step (1/2/4/8 by core count) plus 1 and the max, so a
high-core CPU (e.g. a 192-thread EPYC) shows ~25 tiles instead of one-per-thread and no longer
overflows the card. Unchanged for <=24-core machines.
- Fix: clicking the X (or a row) in an open saved-pools / payout-address dropdown no longer bleeds
through to the thread tiles / Mine button — the custom drawlist hit-tests now gate on
IsPopupOpen(AnyPopup).
- xmrig update button: shows "xmrig releases" when installed >= latest (numeric version compare),
else "Update <latest>"; the "Current: <ver>" text and the button are subtle green when up to date
and subtle orange when an update is available (neutral when either version is unknown).
New i18n keys back-filled across all 8 languages; CJK subset font rebuilt for the new glyphs.
Verified across full-node, lite, and Windows builds; the stepper layout confirmed via the UI sweep.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Fixes all 22 confirmed findings from the mining-tab audit (10 Medium, 12 Low; 0 Critical/High),
adversarially reviewed (6 follow-ups found + fixed, incl. the review-caught idle-auto-start bypass
and a wrong benchmark-restore condition).
Crash-safety & lifecycle:
- M-04: join a stale/finished monitor thread in XmrigManager::start() and ~XmrigManager so an xmrig
crash-then-restart (or quit) no longer std::terminate()s the wallet.
- L-03/L-10: surface an unexpected miner exit once and clear the stale running flag.
UI never blocks (M-03/L-06/L-08/L-09/L-13): pool start/stop now run on a dedicated serialized FIFO
mining-control thread (joined before teardown), so the ~13 call sites don't block the render thread on
stop()'s SIGTERM->SIGKILL->join; the spawn result marshals back to the UI.
Miner-process / pool trust boundary:
- M-01: validate the payout address (util::isValidRecipientAddress) at EVERY start path — the UI gate
AND App::startPoolMining() (idle auto-start / thread scaling) — so a stale/wrong-chain address can't
silently lose rewards.
- M-09: SSRF guard skips the background pool-stats GET for loopback/private/link-local/single-label hosts.
- M-02/L-02: cap the pool-stats + xmrig-API HTTP response bodies.
- L-01: write the xmrig config 0600 at creation (POSIX open with mode) — no world/group-readable window.
- M-10: reject shell-metacharacter binary paths before the version popen (excluding '()' so Program Files
(x86) still works).
Solo mining: M-06/M-08 clamp thread count to [1, cores] at the setgenerate/xmrig boundary; M-07 notify +
don't lie on stop failure.
Correctness: L-05 block-time constant 75->150s (chainparams); M-05 discloses pool-mode "Est. Daily" as a
rough solo-equivalent; L-04/L-11/L-12 benchmark lifecycle (cancel on nav-away / mode-switch with restore,
skip rebalance mid-benchmark); L-07 honor cancel mid-extract in both the xmrig and daemon updaters.
Two new i18n keys back-filled across all 8 languages; CJK subset font rebuilt for the new glyphs.
Verified across full-node, lite, and Windows builds; tests pass.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- balance: inset the address-row favorite (star) button by the card's inner
padding so it mirrors the left margin instead of hugging the card edge.
- mining: remove pool.dragonx.cc from the built-in default pools (pool.dragonx.is
is now the sole default); update the pool-registry test accordingly.
- mining: middle-truncate saved pool-URL and payout-address dropdown rows (new
shared material::TruncateToWidth helper) so a full z-address no longer runs
under the trailing delete (X) button.
- mining: fix the thread-grid cells overflowing the card at >100% display
scaling — the reserved Mine-button width used a raw clamp that didn't scale;
scale it by dp so cols is estimated correctly (no-op at 100%).
Full-node build + test suite green.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- 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>
The last four (more involved) robustness items from the audit:
- deleteBlockchainData: post the deleted-item count to the main thread (via an
atomic, since Notifications isn't thread-safe) and show a completion toast
("Blockchain data deleted (N items). Daemon restarting…") — previously the
result was only logged.
- Pool mining: pool start has a connect delay with no feedback; announce
"Starting pool miner — connecting…" on a successful start and "Pool miner
connected and hashing." once the poll confirms it (contained pool_starting_
flag; the shared mining-toggle state machine is untouched).
- Force Quit (shutdown screen): gate it on the status text having STALLED (a
genuine hang) rather than a bare 10s timer — with a 20s hard-ceiling backstop —
and show a state-aware caution naming the stuck step (force-quitting mid daemon
flush risks the chainstate).
- Benchmark: require a confirming second click that first builds candidates to
estimate the duration ("Benchmark takes ~Ns and interrupts mining"), instead
of interrupting mining immediately.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The app-wide "import-key pattern" fixes (missing guards / untrimmed input / no
re-entrancy protection), from the robustness audit:
- Import-key dialog: unify the type indicator and the RPC dispatch on one
classifier (classifyPrivateKey is now prefix-aware — an "SK..." shielded key no
longer misroutes to the transparent RPC), trim manual input (not just Paste),
and gate both the indicator and the Import button on a shared
isRecognizedPrivateKey() so unrecognized/empty input can't be submitted.
- Shield: guard the submit button on connected + !syncing (like Send), with a
disabled tooltip, instead of firing into a raw daemon error.
- Mining: disable the pool Mine button when the payout address is empty
("enter a payout address first"), and trim the pool URL/worker on persist.
- Console: track in-flight RPC commands (atomic counter + busy() override) so the
input is disabled while a command runs instead of piling up on the worker.
- Maintenance (rescan/repair/delete-chain/reinstall-daemon): re-entrancy guard —
bail with "already in progress" instead of launching a duplicate destructive op.
- Bootstrap dialog: re-attach to an in-flight download on reopen instead of
resetting state and orphaning the running worker.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Follow-up to c83348a: convert the three mining solo-mode header toggles
(idle-mining, thread-scaling, gpu-aware) from the hand-rolled "draw active
pill + glyph, then hit-test" idiom to material::IconButton using the restBg
(active-pill) path. Each keeps its exact behavior pixel-for-pixel: a circular
Primary-tinted pill when active (alpha 60 idle / 40 scale+gpu), a state-colored
glyph (Primary when on, muted when off), hand cursor + tooltip on hover, and
the idle button's cursor save/restore (savedCur, restored at block end) is
preserved. Completes the clean icon-button adoption; the raw-rect IsRectHovered
sites remain intentionally separate (different hit mechanism).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
UI-standardization audit found two dead, contradictory "how to draw a button"
surfaces with zero call sites:
- src/ui/material/components/buttons.h (353 lines: TextButton/Outlined/Contained/
Button(spec)/IconButton/FAB) — included by 3 mining files but never used.
- ApplyTactile (draw_helpers.h) — a retrofit-tactile-onto-plain-button wrapper,
never called.
Remove the file, the 3 dead includes, and ApplyTactile. TactileButton/StyledButton
remain the canonical button helpers. No behavior change.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Split the pool-mode hashrate card into a 25%-width left card + 75% chart so the
Manual/Auto toggle and pool metrics no longer reflow the tab:
- left card: Manual|Auto toggle (with tooltips), a Local/Pool/Shares/Uptime
metric stack, and a fixed-height scrolling pool list — rows click-to-select in
Manual (reusing the existing save+restart path) and show a "mining here" dot in
Auto. Fixed height keeps the card constant as pools are added.
- mode-toggle row: keep the suggested-pools dropdown + auto-mode URL disable;
the toggle and pool list moved into the card.
- mining_controls: show the installed/running miner version ("Current: …")
before and during mining instead of "none".
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add material::Tooltip / BeginTooltip / EndTooltip wrappers (tooltip_style.h)
that scope a small window padding (8x4, dpi-scaled) and ~85% opacity to
tooltips only, then route the tooltip call sites through them. Menus and combo
dropdowns are untouched (they keep the global opaque PopupBg).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Third and largest slice of decomposing mining_tab.cpp. The ~843-line "Controls" card (CPU-core
grid + drag-to-select, mining start/stop button, benchmark + miner-update controls) is moved
verbatim into RenderMiningControls(). mining_tab.cpp is now 839 lines (was 2628 originally).
The most coupled section, so mutated state is passed BY REFERENCE — the benchmark
(ThreadBenchmark&), selected thread count (int&), and drag state (bool&/int&) — with local
reference aliases so the body stays byte-identical and interactions (drag, benchmark, start/stop)
behave exactly as before. Read-only context is passed by value/const; the compiler verified
const-correctness. Local statics inside the block moved with it.
Verified: full-node + Windows + lite build, tests, hygiene, no startup crash.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>