feat(wallet): persist history and surface pending sends

Add an encrypted SQLite transaction history cache with cached tip metadata and
per-address shielded scan progress so startup and full refreshes avoid
re-scanning every z-address while still invalidating on wallet/address/rescan
changes.

Improve wallet history loading by paging transparent transactions, preserving
cached shielded and sent rows, keeping recent/unconfirmed activity visible, and
classifying mining-address receives. Show z_sendmany opid sends immediately in
History and Overview, pin pending rows through refreshes, and apply optimistic
address/balance debits until opids resolve.

Add timestamped RPC console tracing by source/method without logging params or
results, reduce redundant refresh/RPC calls, and cache Explorer recent block
summaries in SQLite.

Expand focused tests for transaction cache encryption, scan-progress
persistence/invalidation, history preservation, operation-status parsing,
pending send visibility, and Explorer/RPC refresh behavior.
This commit is contained in:
2026-05-05 03:22:14 -05:00
parent 948ef419ac
commit 975743f754
43 changed files with 3732 additions and 702 deletions

View File

@@ -11,6 +11,7 @@
#include "../../app.h"
#include "../../util/i18n.h"
#include "../material/draw_helpers.h"
#include "../notifications.h"
#include "../theme.h"
#include "imgui.h"
@@ -171,11 +172,6 @@ public:
ImGui::PopStyleColor();
}
ImGui::Spacing();
ImGui::Spacing();
ImGui::Separator();
ImGui::Spacing();
// Buttons
const char* cancelLabel = TR("cancel");
const char* confirmLabel = TR("confirm_transfer");
@@ -192,6 +188,20 @@ public:
buttonFont->CalcTextSizeA(buttonFontSize, 1000.0f, 0.0f, sendingLabel).x);
float confirmW = std::max(confirmMinW, confirmTextW + buttonPadW);
float totalW = cancelW + confirmW + Layout::spacingMd();
float footerH = ImGui::GetFrameHeight() + ImGui::GetStyle().ItemSpacing.y * 3.0f + 1.0f;
ImGuiViewport* vp = ImGui::GetMainViewport();
float cardBottomY = vp->Pos.y + vp->Size.y * 0.85f;
float footerTopY = cardBottomY - 24.0f * dp - footerH;
float currentY = ImGui::GetCursorScreenPos().y;
if (currentY < footerTopY) {
ImGui::Dummy(ImVec2(0, footerTopY - currentY));
} else {
ImGui::Spacing();
}
ImGui::Separator();
ImGui::Spacing();
float rowStartX = ImGui::GetCursorPosX();
float contentW = ImGui::GetContentRegionAvail().x;
ImGui::SetCursorPosX(rowStartX + std::max(0.0f, (contentW - totalW) * 0.5f));
@@ -209,11 +219,14 @@ public:
[](bool ok, const std::string& result) {
s_sending = false;
s_success = ok;
if (ok)
s_resultMsg = result; // opid
else
s_resultMsg = result; // error message
s_resultMsg = result;
if (ok) {
Notifications::instance().success(TR("transfer_sent_desc"));
} else {
Notifications::instance().error(result.empty() ? TR("transfer_failed") : result);
}
});
s_open = false;
}
ImGui::EndDisabled();