#include "mining_tab_helpers.h" #include "../../util/local_time.h" #include #include #include #include #include namespace dragonx { namespace ui { int GetMaxMiningThreads() { int hardwareThreads = static_cast(std::thread::hardware_concurrency()); return std::max(1, hardwareThreads); } int ClampMiningThreads(int requestedThreads, int maxThreads) { int boundedMax = std::max(1, maxThreads); return std::clamp(requestedThreads, 1, boundedMax); } bool IsPoolMiningActive(bool poolMode, bool xmrigRunning, bool soloMiningRunning) { return poolMode ? xmrigRunning : (soloMiningRunning || xmrigRunning); } std::string FormatHashrate(double hashrate) { char buffer[64]; if (hashrate >= 1e12) { snprintf(buffer, sizeof(buffer), "%.2f TH/s", hashrate / 1e12); } else if (hashrate >= 1e9) { snprintf(buffer, sizeof(buffer), "%.2f GH/s", hashrate / 1e9); } else if (hashrate >= 1e6) { snprintf(buffer, sizeof(buffer), "%.2f MH/s", hashrate / 1e6); } else if (hashrate >= 1e3) { snprintf(buffer, sizeof(buffer), "%.2f KH/s", hashrate / 1e3); } else { snprintf(buffer, sizeof(buffer), "%.2f H/s", hashrate); } return std::string(buffer); } std::string FormatFeePercent(double feePercent) { // Whole fees read "1"; fractional ones keep only their significant decimals // ("1.5", "0.9", "1.25") with no trailing zeros. Capped at 2 dp — finer than // any pool advertises, and the caller appends the "%". char buffer[32]; snprintf(buffer, sizeof(buffer), "%.2f", feePercent); std::string s(buffer); if (s.find('.') != std::string::npos) { s.erase(s.find_last_not_of('0') + 1); if (!s.empty() && s.back() == '.') s.pop_back(); } return s; } double EstimateHoursToBlock(double localHashrate, double networkHashrate, double difficulty) { (void)difficulty; if (localHashrate <= 0.0 || networkHashrate <= 0.0) return 0.0; double blocksPerHour = 3600.0 / 150.0; // DragonX mainnet target spacing is 150s (chainparams) (L-05) double share = localHashrate / networkHashrate; if (share <= 0.0) return 0.0; return 1.0 / (blocksPerHour * share); } std::string FormatEstTime(double estimatedHours) { char buffer[64]; if (estimatedHours <= 0.0) { return "N/A"; } else if (estimatedHours < 1.0) { snprintf(buffer, sizeof(buffer), "~%.0f min", estimatedHours * 60.0); } else if (estimatedHours < 24.0) { snprintf(buffer, sizeof(buffer), "~%.1f hrs", estimatedHours); } else if (estimatedHours < 168.0) { snprintf(buffer, sizeof(buffer), "~%.1f days", estimatedHours / 24.0); } else { snprintf(buffer, sizeof(buffer), "~%.1f weeks", estimatedHours / 168.0); } return std::string(buffer); } MiningEarningsTotals ComputeMiningEarnings(const std::vector& txs, int filter, bool soloSupported, bool poolMode, std::int64_t todayStart, std::int64_t yesterdayStart) { MiningEarningsTotals t; for (const auto& tx : txs) { bool isSoloMined = (tx.type == "generate" || tx.type == "immature" || tx.type == "mined"); bool isPoolPayout = (tx.type == "receive" && !tx.memo.empty() && tx.memo.find("Mining Pool payout") != std::string::npos); if (!(isSoloMined || isPoolPayout)) continue; // Apply earnings filter if (!soloSupported) { if (filter == 1 && !isPoolPayout) continue; } else { if (filter == 1 && !isSoloMined) continue; if (filter == 2 && !isPoolPayout) continue; } double amt = std::abs(tx.amount); t.allTime += amt; t.allTimeCount++; if (tx.timestamp >= todayStart) { t.today += amt; t.todayCount++; } else if (tx.timestamp >= yesterdayStart) { t.yesterday += amt; t.yesterdayCount++; } // Separate solo blocks from pool payouts based on current mode bool showInCurrentMode = poolMode ? isPoolPayout : isSoloMined; if (showInCurrentMode && t.recent.size() < 4) t.recent.push_back({tx.timestamp, amt, tx.confirmations, tx.confirmations >= 100, tx.txid, isPoolPayout}); } return t; } const MiningEarningsTotals& MiningEarningsCache::get(const MiningEarningsKey& key, const std::vector& txs, std::int64_t nowMs) { if (!valid_ || !(key == key_) || IntervalElapsed(nowMs, computedAtMs_, kMaxAgeMs)) { totals_ = ComputeMiningEarnings(txs, key.filter, key.soloSupported, key.poolMode, key.todayStart, key.todayStart - 86400); // 86400: as before key_ = key; computedAtMs_ = nowMs; valid_ = true; ++computes_; } return totals_; } bool IntervalElapsed(std::int64_t nowMs, std::int64_t lastMs, std::int64_t minMs) { return nowMs < lastMs || nowMs - lastMs >= minMs; } std::int64_t LocalDayStartMemo::get(std::int64_t now) { if (now == now_) return start_; std::tm local{}; util::localTime(static_cast(now), local); // same localtime_r / localtime_s as before local.tm_hour = 0; local.tm_min = 0; local.tm_sec = 0; start_ = (std::int64_t)mktime(&local); now_ = now; return start_; } } // namespace ui } // namespace dragonx