// DragonX Wallet - ImGui Edition // Copyright 2024-2026 The Hush Developers // Released under the GPLv3 // // A tiny, pure block-sync rate estimator for the status-bar / peers-card ETA. Pure (no ImGui, no App): // App owns one instance, feeds it the current height + a monotonic clock once per frame while syncing, // and resets it on connect / disconnect / rescan / restart so a height drop never produces a stale or // absurd ("412h") ETA. #pragma once #include #include namespace dragonx { namespace util { class SyncRateEstimator { public: void reset() { prevBlocks_ = -1; prevTime_ = 0.0; rate_ = 0.0; } // Call once per frame while syncing. `now` is monotonic seconds (e.g. ImGui::GetTime()). void update(int blocks, double now) { // First sample, a rescan/restart height drop, or a clock reset → re-baseline, don't compute. if (prevBlocks_ < 0 || blocks < prevBlocks_ || now < prevTime_) { prevBlocks_ = blocks; prevTime_ = now; rate_ = 0.0; return; } const double dt = now - prevTime_; if (blocks > prevBlocks_) { if (dt > 0.5) { const double raw = (blocks - prevBlocks_) / dt; rate_ = rate_ > 0.0 ? rate_ * 0.7 + raw * 0.3 : raw; // smooth (same alpha as the old code) prevBlocks_ = blocks; prevTime_ = now; } } else if (dt > 10.0) { // stalled: decay and re-baseline the clock rate_ *= 0.5; prevTime_ = now; if (rate_ < 0.1) rate_ = 0.0; } } double rate() const { return rate_; } // blocks/sec, 0 when unknown // <= 0 when unknown. Capped at ~1 year so a tiny rate can't overflow. long long etaSeconds(int blocksLeft) const { if (rate_ <= 0.1 || blocksLeft <= 0) return -1; const double s = blocksLeft / rate_; return s > 3.15e7 ? 31500000LL : static_cast(s); } private: int prevBlocks_ = -1; // -1 = unset (distinct from a legitimate height 0) double prevTime_ = 0.0; double rate_ = 0.0; }; // Human ETA with days, e.g. "3d 4h", "5h 12m", "7m 9s", "42s". English unit letters (as the old code). inline void formatEta(long long s, char* out, std::size_t n) { if (s >= 86400) std::snprintf(out, n, "%lldd %lldh", s / 86400, (s % 86400) / 3600); else if (s >= 3600) std::snprintf(out, n, "%lldh %lldm", s / 3600, (s % 3600) / 60); else if (s >= 60) std::snprintf(out, n, "%lldm %llds", s / 60, s % 60); else std::snprintf(out, n, "%llds", s); } } // namespace util } // namespace dragonx