feat: RPC caching, background decrypt import, fast-lane peers, mining fix
RPC client: - Add call() overload with per-call timeout parameter - z_exportwallet uses 300s, z_importwallet uses 1200s timeout Decrypt wallet (app_security.cpp, app.cpp): - Show per-step and overall elapsed timers during decrypt flow - Reduce dialog to 5 steps; close before key import begins - Run z_importwallet on detached background thread - Add pulsing "Importing keys..." status bar indicator - Report success/failure via notifications instead of dialog RPC caching (app_network.cpp, app.h): - Cache z_viewtransaction results in viewtx_cache_ across refresh cycles - Skip RPC calls for already-cached txids (biggest perf win) - Build confirmed_tx_cache_ for deeply-confirmed transactions - Clear all caches on disconnect - Remove unused refreshTransactions() dead code Peers (app_network.cpp, peers_tab.cpp): - Route refreshPeerInfo() through fast_worker_ to avoid head-of-line blocking - Replace footer "Refresh Peers" button with ICON_MD_REFRESH in toggle header - Refresh button triggers both peer list and full blockchain data refresh Mining (mining_tab.cpp): - Allow pool mining toggle when blockchain is not synced - Pool mining only needs xmrig, not local daemon sync
This commit is contained in:
79
src/app.cpp
79
src/app.cpp
@@ -68,6 +68,7 @@
|
||||
|
||||
#include <cstdio>
|
||||
#include <ctime>
|
||||
#include <algorithm>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <fstream>
|
||||
@@ -273,6 +274,8 @@ void App::update()
|
||||
refresh_timer_ += io.DeltaTime;
|
||||
price_timer_ += io.DeltaTime;
|
||||
fast_refresh_timer_ += io.DeltaTime;
|
||||
tx_age_timer_ += io.DeltaTime;
|
||||
opid_poll_timer_ += io.DeltaTime;
|
||||
|
||||
// Fast refresh (mining stats + daemon memory) every second
|
||||
// Skip when wallet is locked — no need to poll, and queued tasks
|
||||
@@ -443,6 +446,64 @@ void App::update()
|
||||
}
|
||||
}
|
||||
|
||||
// Poll pending z_sendmany operations for completion
|
||||
if (opid_poll_timer_ >= OPID_POLL_INTERVAL && !pending_opids_.empty()
|
||||
&& state_.connected && fast_worker_) {
|
||||
opid_poll_timer_ = 0.0f;
|
||||
auto opids = pending_opids_; // copy for worker thread
|
||||
fast_worker_->post([this, opids]() -> rpc::RPCWorker::MainCb {
|
||||
auto* rpc = (fast_rpc_ && fast_rpc_->isConnected()) ? fast_rpc_.get() : rpc_.get();
|
||||
if (!rpc) return [](){};
|
||||
json ids = json::array();
|
||||
for (const auto& id : opids) ids.push_back(id);
|
||||
json result;
|
||||
try {
|
||||
result = rpc->call("z_getoperationstatus", {ids});
|
||||
} catch (...) {
|
||||
return [](){};
|
||||
}
|
||||
// Collect completed/failed opids
|
||||
std::vector<std::string> done;
|
||||
bool anySuccess = false;
|
||||
for (const auto& op : result) {
|
||||
std::string status = op.value("status", "");
|
||||
std::string opid = op.value("id", "");
|
||||
if (status == "success") {
|
||||
done.push_back(opid);
|
||||
anySuccess = true;
|
||||
} else if (status == "failed") {
|
||||
done.push_back(opid);
|
||||
std::string msg = "Transaction failed";
|
||||
if (op.contains("error") && op["error"].contains("message"))
|
||||
msg = op["error"]["message"].get<std::string>();
|
||||
// Capture for main thread
|
||||
return [this, done, msg]() {
|
||||
ui::Notifications::instance().error(msg);
|
||||
for (const auto& id : done) {
|
||||
pending_opids_.erase(
|
||||
std::remove(pending_opids_.begin(), pending_opids_.end(), id),
|
||||
pending_opids_.end());
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
return [this, done, anySuccess]() {
|
||||
for (const auto& id : done) {
|
||||
pending_opids_.erase(
|
||||
std::remove(pending_opids_.begin(), pending_opids_.end(), id),
|
||||
pending_opids_.end());
|
||||
}
|
||||
if (anySuccess) {
|
||||
// Transaction confirmed by daemon — force immediate data refresh
|
||||
transactions_dirty_ = true;
|
||||
addresses_dirty_ = true;
|
||||
last_tx_block_height_ = -1;
|
||||
refresh_timer_ = REFRESH_INTERVAL;
|
||||
}
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
// Regular refresh every 5 seconds
|
||||
// Skip when wallet is locked — same reason as above.
|
||||
if (refresh_timer_ >= REFRESH_INTERVAL) {
|
||||
@@ -1288,6 +1349,21 @@ void App::renderStatusBar()
|
||||
state_.mining.localHashrate);
|
||||
}
|
||||
|
||||
// Decrypt-import background task indicator
|
||||
if (decrypt_import_active_) {
|
||||
ImGui::SameLine(0, sbSectionGap);
|
||||
ImGui::TextDisabled("|");
|
||||
ImGui::SameLine(0, sbSeparatorGap);
|
||||
ImGui::PushFont(ui::material::Type().iconSmall());
|
||||
float pulse = 0.6f + 0.4f * sinf((float)ImGui::GetTime() * 3.0f);
|
||||
ImGui::TextColored(ImVec4(0.6f, 0.8f, 1.0f, pulse), ICON_MD_LOCK_OPEN);
|
||||
ImGui::PopFont();
|
||||
ImGui::SameLine(0, sbIconTextGap);
|
||||
int dots = (int)(ImGui::GetTime() * 2.0f) % 4;
|
||||
const char* dotStr = (dots == 0) ? "." : (dots == 1) ? ".." : (dots == 2) ? "..." : "";
|
||||
ImGui::TextColored(ImVec4(0.6f, 0.8f, 1.0f, 1.0f), "Importing keys%s", dotStr);
|
||||
}
|
||||
|
||||
// Right side: connection status message (if any) + version always at far right
|
||||
float rightStart = ImGui::GetWindowWidth() - sbRightContentOff;
|
||||
if (!connection_status_.empty() && connection_status_ != "Connected") {
|
||||
@@ -1632,6 +1708,9 @@ void App::renderAntivirusHelpDialog()
|
||||
void App::refreshNow()
|
||||
{
|
||||
refresh_timer_ = REFRESH_INTERVAL; // Trigger immediate refresh
|
||||
transactions_dirty_ = true; // Force transaction list update
|
||||
addresses_dirty_ = true; // Force address/balance update
|
||||
last_tx_block_height_ = -1; // Reset tx cache
|
||||
}
|
||||
|
||||
void App::handlePaymentURI(const std::string& uri)
|
||||
|
||||
Reference in New Issue
Block a user