feat(wallet): add a Compact action to reclaim space after consolidating
Consolidating reduces the note count and stops the wallet growing, but Berkeley
DB never shrinks wallet.dat in place, so the freed space isn't returned to the OS
and the displayed size doesn't drop. Add an explicit "Compact wallet…" action
(next to "Consolidate notes…" in the large-wallet area of Node & Security) that
rewrites the file into a fresh, compact one.
App::compactWallet() arms the daemon's -salvagewallet flag for the next start and
calls restartDaemon() (reusing its full-node / busy / lifecycle guards); the
daemon rewrites wallet.dat into a smaller file, keeps the old one as a timestamped
.bak, and — because -salvagewallet implies -rescan — re-scans the chain. If the
restart is refused the salvage flag is disarmed so it can't fire on a later
restart. A confirmation overlay (mirroring the repair-wallet one) explains the
restart + rescan + that funds/balance are safe and a backup is kept. New strings
wallet_size_compact / tt_wallet_size_compact / compact_started /
confirm_compact_wallet_{title,msg,safe} / compact_wallet_confirm.
Build + tests + hygiene green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -801,6 +801,10 @@ public:
|
||||
* Shows "Restarting daemon..." in the loading overlay while the daemon cycles.
|
||||
*/
|
||||
void restartDaemon();
|
||||
// Compact wallet.dat to reclaim the space freed by consolidating notes: Berkeley DB never shrinks a
|
||||
// file in place, so a restart with -salvagewallet rewrites it into a fresh, compact file (keeping a
|
||||
// backup). -salvagewallet implies a full rescan, so this restarts the node and re-scans the chain.
|
||||
void compactWallet();
|
||||
// A newer daemon binary is installed but the running node is still the old one until a restart.
|
||||
void markDaemonRestartPending() { daemon_restart_pending_.store(true); }
|
||||
bool daemonRestartPending() const { return daemon_restart_pending_.load(); }
|
||||
|
||||
@@ -6500,6 +6500,24 @@ void App::maybeWarnLargeWallet()
|
||||
TR("wallet_size_consolidate"), 12.0f);
|
||||
}
|
||||
|
||||
void App::compactWallet()
|
||||
{
|
||||
auto& n = ui::Notifications::instance();
|
||||
if (!supportsFullNodeLifecycleActions() || !daemon_controller_) {
|
||||
n.warning(TR("appx_fullnode_lifecycle_unavailable_lite"));
|
||||
return;
|
||||
}
|
||||
// Consolidation frees internal BDB pages but never returns the space to the OS; -salvagewallet on the
|
||||
// next start rewrites wallet.dat into a fresh, compact file (and keeps the old one as a timestamped
|
||||
// .bak). It implies a full rescan, so restartDaemon() takes the node down and back up re-scanning.
|
||||
daemon_controller_->setSalvageOnNextStart(true);
|
||||
restartDaemon(); // does its own full-node / busy / lifecycle guards and will refuse if the node is busy
|
||||
if (daemon_restarting_.load())
|
||||
n.info(TR("compact_started"));
|
||||
else
|
||||
daemon_controller_->setSalvageOnNextStart(false); // the restart was refused — disarm the stray salvage
|
||||
}
|
||||
|
||||
// Complementary on-disk safety net (full-node) for a wallet salvage we did NOT witness this launch — it
|
||||
// happened on a prior run, or under an external daemon whose startup output we never captured, so
|
||||
// detectWalletAutoRecovery() never fired. If the active wallet loads EMPTY while a sibling wallet file in
|
||||
|
||||
@@ -186,6 +186,7 @@ struct SettingsPageState {
|
||||
bool rescan_probe_failed = false; // the probe could not tell (node busy): warn before the -rescan restart
|
||||
int rescan_probe_seq = 0; // the probe is async: a late result for an earlier opening is dropped
|
||||
bool confirm_repair_wallet = false;
|
||||
bool confirm_compact_wallet = false;
|
||||
bool confirm_reinstall_daemon = false;
|
||||
// Cached daemon-binary status for the "daemon binary" panel (loaded once / on Refresh,
|
||||
// since reading the installed binary to scan its version is a one-off disk read).
|
||||
@@ -2383,6 +2384,12 @@ void RenderSettingsPage(App* app) {
|
||||
ICON_MD_CALL_MERGE, material::ActionTier::Secondary))
|
||||
ShieldDialog::showConsolidate();
|
||||
if (ImGui::IsItemHovered()) material::Tooltip("%s", TR("tt_merge"));
|
||||
ImGui::SameLine();
|
||||
// Compact reclaims the file space consolidation frees (BDB won't shrink in place).
|
||||
if (material::ActionButton("##walletcompact", TR("wallet_size_compact"),
|
||||
ICON_MD_COMPRESS, material::ActionTier::Secondary))
|
||||
s_settingsState.confirm_compact_wallet = true;
|
||||
if (ImGui::IsItemHovered()) material::Tooltip("%s", TR("tt_wallet_size_compact"));
|
||||
}
|
||||
|
||||
// Row 3: folder buttons (their own row so the path gets the full width).
|
||||
@@ -3466,6 +3473,35 @@ void RenderSettingsPage(App* app) {
|
||||
}
|
||||
}
|
||||
|
||||
// Confirm: compact wallet.dat to reclaim the space consolidation freed (rewrite via -salvagewallet,
|
||||
// which restarts the node and re-scans the chain). A backup of the current wallet is kept.
|
||||
if (s_settingsState.confirm_compact_wallet) {
|
||||
if (BeginOverlayDialog(TR("confirm_compact_wallet_title"), &s_settingsState.confirm_compact_wallet, 500.0f, 0.94f)) {
|
||||
material::DialogWarningHeader(TR("warning"), material::WarningVec4());
|
||||
|
||||
ImGui::Spacing();
|
||||
ImGui::TextWrapped("%s", TR("confirm_compact_wallet_msg"));
|
||||
ImGui::Spacing();
|
||||
ImGui::TextColored(material::SuccessVec4(), "%s", TR("confirm_compact_wallet_safe"));
|
||||
ImGui::Spacing();
|
||||
ImGui::Separator();
|
||||
ImGui::Spacing();
|
||||
|
||||
bool doCancel = false, doConfirm = false;
|
||||
material::DialogConfirmFooter(TrId("cancel", "compact_wallet_cancel").c_str(),
|
||||
TrId("compact_wallet_confirm", "compact_wallet_confirm").c_str(),
|
||||
false, doCancel, doConfirm);
|
||||
if (doCancel) {
|
||||
s_settingsState.confirm_compact_wallet = false;
|
||||
}
|
||||
if (doConfirm) {
|
||||
app->compactWallet();
|
||||
s_settingsState.confirm_compact_wallet = false;
|
||||
}
|
||||
EndOverlayDialog();
|
||||
}
|
||||
}
|
||||
|
||||
// Confirm: reinstall the bundled daemon binary (stop → overwrite → restart)
|
||||
if (s_settingsState.confirm_reinstall_daemon) {
|
||||
if (BeginOverlayDialog(TR("confirm_reinstall_daemon_title"), &s_settingsState.confirm_reinstall_daemon, 500.0f, 0.94f)) {
|
||||
|
||||
@@ -878,6 +878,13 @@ void I18n::loadBuiltinEnglish()
|
||||
strings_["wallet_size_auto_info"] = "Your wallet has built up a lot of notes \xE2\x80\x94 separate pieces of received funds that enlarge the file and slow syncing. Auto-consolidation is quietly merging them in the background to keep it small and fast, so there's nothing you need to do.";
|
||||
strings_["tt_wallet_size_warn"] = "Each payment arrives as a separate shielded note, and every note carries witness data that grows the wallet file and slows scans. Merging many notes into one per address shrinks it \xE2\x80\x94 your funds and balance are unchanged. Back up your seed first. You can also turn on Auto-consolidate in Settings to do this automatically in the background.";
|
||||
strings_["wallet_size_consolidate"] = "Consolidate notes\xE2\x80\xA6";
|
||||
strings_["wallet_size_compact"] = "Compact wallet\xE2\x80\xA6";
|
||||
strings_["tt_wallet_size_compact"] = "Reclaim the disk space freed by consolidating. Berkeley DB can't shrink the file in place, so this rewrites wallet.dat into a smaller file and restarts the node with a full rescan (can take a while). A backup of the current wallet is kept.";
|
||||
strings_["compact_started"] = "Compacting wallet \xE2\x80\x94 the node is restarting and will re-scan the chain.";
|
||||
strings_["confirm_compact_wallet_title"] = "Compact wallet";
|
||||
strings_["confirm_compact_wallet_msg"] = "Consolidating merged your notes, but the wallet file can't shrink on its own \xE2\x80\x94 the node has to rewrite it to reclaim the freed space. This restarts the node and re-scans the blockchain, which can take a while on a large wallet.";
|
||||
strings_["confirm_compact_wallet_safe"] = "Your funds and balance are safe \xE2\x80\x94 a timestamped backup of the current wallet is kept.";
|
||||
strings_["compact_wallet_confirm"] = "Compact";
|
||||
strings_["settings_debug_changed"] = "Debug categories changed \xe2\x80\x94 restart daemon to apply";
|
||||
strings_["settings_auto_detected"] = "Auto-detected from DRAGONX.conf";
|
||||
strings_["settings_visual_effects"] = "Visual Effects";
|
||||
|
||||
Reference in New Issue
Block a user