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>
79 lines
3.4 KiB
C++
79 lines
3.4 KiB
C++
#pragma once
|
|
|
|
#include <cstddef>
|
|
#include <cstdint>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#include "data/wallet_state.h" // TransactionInfo
|
|
|
|
namespace dragonx {
|
|
namespace ui {
|
|
|
|
int GetMaxMiningThreads();
|
|
int ClampMiningThreads(int requestedThreads, int maxThreads);
|
|
bool IsPoolMiningActive(bool poolMode, bool xmrigRunning, bool soloMiningRunning);
|
|
std::string FormatHashrate(double hashrate);
|
|
std::string FormatFeePercent(double feePercent);
|
|
double EstimateHoursToBlock(double localHashrate, double networkHashrate, double difficulty);
|
|
std::string FormatEstTime(double estimatedHours);
|
|
|
|
// ---- Mining earnings card (Today / Yesterday / All time + the 4 most recent rows) ----
|
|
// Stored BY VALUE: never point into WalletState::transactions (a refresh replaces / reallocates it).
|
|
struct MiningEarningsRecentTx {
|
|
std::int64_t timestamp = 0;
|
|
double amount = 0.0;
|
|
int confirmations = 0;
|
|
bool mature = false;
|
|
std::string txid;
|
|
bool isPoolPayout = false;
|
|
};
|
|
struct MiningEarningsTotals {
|
|
double today = 0.0, yesterday = 0.0, allTime = 0.0;
|
|
int todayCount = 0, yesterdayCount = 0, allTimeCount = 0;
|
|
std::vector<MiningEarningsRecentTx> recent; // <= 4, in tx-list order
|
|
};
|
|
// The earnings card's former inline loop, verbatim. filter: 0 All, 1 Solo, 2 Pool (the card's filter pill).
|
|
MiningEarningsTotals ComputeMiningEarnings(const std::vector<TransactionInfo>& txs, int filter,
|
|
bool soloSupported, bool poolMode,
|
|
std::int64_t todayStart, std::int64_t yesterdayStart);
|
|
// Every input the totals depend on: equal keys => the cached totals are still valid.
|
|
struct MiningEarningsKey {
|
|
std::uint64_t txRevision = 0; // WalletState::tx_revision (bumped by every write to `transactions`)
|
|
std::size_t txCount = 0; // belt: a future writer that skips the bump but changes the row count
|
|
int filter = 0;
|
|
bool soloSupported = false;
|
|
bool poolMode = false; // picks the recent-4 rows (solo blocks vs pool payouts)
|
|
std::int64_t todayStart = 0; // local midnight; yesterday = todayStart - 86400, as before
|
|
bool operator==(const MiningEarningsKey& o) const {
|
|
return txRevision == o.txRevision && txCount == o.txCount && filter == o.filter &&
|
|
soloSupported == o.soloSupported && poolMode == o.poolMode && todayStart == o.todayStart;
|
|
}
|
|
};
|
|
class MiningEarningsCache {
|
|
public:
|
|
static constexpr std::int64_t kMaxAgeMs = 2000; // bounds staleness if a future writer skips the bump
|
|
const MiningEarningsTotals& get(const MiningEarningsKey& key, const std::vector<TransactionInfo>& txs,
|
|
std::int64_t nowMs);
|
|
int computeCount() const { return computes_; } // tests
|
|
private:
|
|
bool valid_ = false;
|
|
MiningEarningsKey key_;
|
|
std::int64_t computedAtMs_ = 0;
|
|
MiningEarningsTotals totals_;
|
|
int computes_ = 0;
|
|
};
|
|
// True when a sample taken at lastMs is at least minMs old (or the clock went backwards).
|
|
bool IntervalElapsed(std::int64_t nowMs, std::int64_t lastMs, std::int64_t minMs);
|
|
// Local midnight for `now` (the same localtime + mktime as before). A pure function of the second, so it is
|
|
// recomputed only when `now` changes instead of on every frame (bit-identical result, DST quirks included).
|
|
class LocalDayStartMemo {
|
|
public:
|
|
std::int64_t get(std::int64_t now);
|
|
private:
|
|
std::int64_t now_ = INT64_MIN, start_ = 0;
|
|
};
|
|
|
|
} // namespace ui
|
|
} // namespace dragonx
|