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:
dan_s
2026-03-04 15:12:24 -06:00
parent 7fb1f1de9d
commit 0ca1caf148
8 changed files with 459 additions and 270 deletions

View File

@@ -505,6 +505,32 @@ void RenderPeersTab(App* app)
}
if (ImGui::IsItemHovered()) ImGui::SetMouseCursor(ImGuiMouseCursor_Hand);
// Refresh button — top-right of the toggle header line
{
ImFont* iconFont = Type().iconMed();
float iconSz = iconFont->LegacySize;
float btnPad = Layout::spacingSm();
float btnX = ImGui::GetWindowPos().x + availWidth - iconSz - btnPad;
float btnY = toggleY + (toggleH - iconSz) * 0.5f;
ImGui::SetCursorScreenPos(ImVec2(btnX, btnY));
ImGui::PushID("##peersRefresh");
if (ImGui::InvisibleButton("##btn", ImVec2(iconSz + btnPad, iconSz + btnPad))) {
app->refreshPeerInfo();
app->refreshNow();
}
bool hovered = ImGui::IsItemHovered();
if (hovered) ImGui::SetMouseCursor(ImGuiMouseCursor_Hand);
ImU32 iconCol = hovered ? OnSurface() : OnSurfaceMedium();
// Centre icon within the invisible button
float drawX = btnX + (iconSz + btnPad - iconSz) * 0.5f;
float drawY = btnY + (iconSz + btnPad - iconSz) * 0.5f;
dl->AddText(iconFont, iconSz, ImVec2(drawX, drawY), iconCol, ICON_MD_REFRESH);
if (hovered) {
ImGui::SetTooltip("Refresh peers & blockchain");
}
ImGui::PopID();
}
ImGui::SetCursorScreenPos(ImVec2(ImGui::GetWindowPos().x, toggleY + toggleH));
}
@@ -782,22 +808,13 @@ void RenderPeersTab(App* app)
}
// ================================================================
// Footer — Refresh + Clear Bans (material styled)
// Footer — Clear Bans (material styled)
// ================================================================
{
if (s_show_banned && !state.bannedPeers.empty()) {
ImGui::BeginDisabled(!app->isConnected());
if (TactileSmallButton("Refresh Peers", S.resolveFont("button"))) {
app->refreshPeerInfo();
if (TactileSmallButton("Clear All Bans", S.resolveFont("button"))) {
app->clearBans();
}
if (s_show_banned && !state.bannedPeers.empty()) {
ImGui::SameLine();
if (TactileSmallButton("Clear All Bans", S.resolveFont("button"))) {
app->clearBans();
}
}
ImGui::EndDisabled();
}