The Mining tab's earnings card walked all N wallet transactions on
every frame to total Today / Yesterday / All time and pick the 4 most
recent rows: four string compares per transaction plus a memo search
on receives. It also ran localtime and mktime every frame to find
local midnight.
The pass is now a pure function behind a one-slot cache keyed on
WalletState::tx_revision, the transaction count, the filter pill, the
Solo/Pool mode, solo support and local midnight, with a 2 s maximum
age as a safety net. It reruns only when one of those changes or the
2 s age runs out, instead of every frame. The totals are bit-identical
(same loop, same summation order), and crossing local midnight still
moves Today into Yesterday at once.
Local midnight is recomputed only when the clock second changes,
through the shared util::localTime; a failed localtime now yields a
zeroed struct instead of an uninitialised one. The "x ago" labels and
Est. Daily are still computed per frame.
Co-Authored-By: Claude Opus 5.5 <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>
Several related mining-tab pool improvements:
- Report the default pool fee correctly: pool.dragonx.is is 1%, not 0%.
The registry constant was hardcoded to 0. It now also fetches the live
poolFee from the pool's /api/stats alongside hashrate (no extra
request), so the displayed fee self-corrects and falls back to the
compile-time value only when the fetch hasn't landed.
- Show fractional fees: new FormatFeePercent trims trailing zeros so
whole fees read "1%" and fractional ones keep their decimals ("1.5%").
- Surface saved + custom pools in the pool list card: the list is now
the union of the official pools, the user's saved favorites, and the
currently-mined pool (effectivePools), each a selectable, endpoint-
deduped row. Previously the card only showed the hardcoded knownPools().
- Fix the xmrig "user" field: the "Payout Address" field now drives the
pool login rewards are credited to (resolveMiningUserAddress), instead
of being written only to "pass" while "user" was auto-derived from the
wallet's own first z-address -- which silently ignored a configured
payout address and could route rewards to the wrong address.
Unit tests cover parsePoolFee, FormatFeePercent, effectivePools, and
resolveMiningUserAddress; full app + ObsidianDragonTests build clean.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>