feat(fullnode): add "Repair Wallet" (-zapwallettxes=2) to Settings
When a note's stored record is corrupt or its tx isn't in the canonical chain, z_sendmany fails to build a valid sapling spend proof even after a full -rescan, because a plain rescan replays witnesses but keeps the existing tx/note records. The zcashd repair for this is -zapwallettxes=2, which deletes all wallet tx/note records and rebuilds them from the chain (keys/addresses preserved). Adds a RepairWallet lifecycle operation that mirrors the existing -rescan plumbing (one-shot zapOnNextStart flag on the embedded daemon; -zapwallettxes=2 implies and supersedes -rescan), an App::repairWallet() that reuses the rescan status UI (so the status bar + warmup-end completion detection apply), and a confirmed "Repair Wallet" button + dialog in Settings → node maintenance (embedded daemon only). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -146,6 +146,7 @@ struct SettingsPageState {
|
||||
bool confirm_clear_ztx = false;
|
||||
bool confirm_delete_blockchain = false;
|
||||
bool confirm_rescan = false;
|
||||
bool confirm_repair_wallet = false;
|
||||
bool confirm_restart_daemon = false;
|
||||
bool confirm_lite_redownload = false;
|
||||
effects::ScrollFadeShader fade_shader;
|
||||
@@ -2044,6 +2045,16 @@ void RenderSettingsPage(App* app) {
|
||||
}
|
||||
if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled)) ImGui::SetTooltip("%s", TR("tt_delete_blockchain"));
|
||||
ImGui::EndDisabled();
|
||||
|
||||
// Repair wallet (-zapwallettxes=2): wipe & rebuild wallet tx/note records from
|
||||
// the chain (keys kept). Fixes notes that fail to spend after a rescan.
|
||||
ImGui::SetCursorScreenPos(ImVec2(leftX, ImGui::GetCursorScreenPos().y + Layout::spacingSm()));
|
||||
ImGui::BeginDisabled(!app->isUsingEmbeddedDaemon());
|
||||
if (TactileButton(TR("repair_wallet"), ImVec2(0, 0), btnFont)) {
|
||||
s_settingsState.confirm_repair_wallet = true;
|
||||
}
|
||||
if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled)) ImGui::SetTooltip("%s", TR("tt_repair_wallet"));
|
||||
ImGui::EndDisabled();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2647,6 +2658,36 @@ void RenderSettingsPage(App* app) {
|
||||
}
|
||||
}
|
||||
|
||||
// Confirm: repair wallet (-zapwallettxes=2 — wipe & rebuild wallet tx records, then rescan)
|
||||
if (s_settingsState.confirm_repair_wallet) {
|
||||
if (BeginOverlayDialog(TR("confirm_repair_wallet_title"), &s_settingsState.confirm_repair_wallet, 500.0f, 0.94f)) {
|
||||
ImGui::PushFont(Type().iconLarge());
|
||||
ImGui::TextColored(ImVec4(1.0f, 0.8f, 0.2f, 1.0f), ICON_MD_WARNING);
|
||||
ImGui::PopFont();
|
||||
ImGui::SameLine();
|
||||
ImGui::TextColored(ImVec4(1.0f, 0.8f, 0.2f, 1.0f), "%s", TR("warning"));
|
||||
|
||||
ImGui::Spacing();
|
||||
ImGui::TextWrapped("%s", TR("confirm_repair_wallet_msg"));
|
||||
ImGui::Spacing();
|
||||
ImGui::TextColored(ImVec4(0.3f, 0.8f, 0.3f, 1.0f), "%s", TR("confirm_repair_wallet_safe"));
|
||||
ImGui::Spacing();
|
||||
ImGui::Separator();
|
||||
ImGui::Spacing();
|
||||
|
||||
float btnW = (ImGui::GetContentRegionAvail().x - ImGui::GetStyle().ItemSpacing.x) * 0.5f;
|
||||
if (ImGui::Button(TrId("cancel", "repair_wallet_cancel").c_str(), ImVec2(btnW, 40))) {
|
||||
s_settingsState.confirm_repair_wallet = false;
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button(TrId("repair_wallet", "repair_wallet_confirm").c_str(), ImVec2(btnW, 40))) {
|
||||
app->repairWallet();
|
||||
s_settingsState.confirm_repair_wallet = false;
|
||||
}
|
||||
EndOverlayDialog();
|
||||
}
|
||||
}
|
||||
|
||||
// Confirm: restart daemon (briefly drops the connection to apply changed options)
|
||||
if (s_settingsState.confirm_restart_daemon) {
|
||||
if (BeginOverlayDialog(TR("confirm_restart_daemon_title"), &s_settingsState.confirm_restart_daemon, 500.0f, 0.94f)) {
|
||||
|
||||
Reference in New Issue
Block a user