From b01d475cd05c229c382096393d120f8843dcaae6 Mon Sep 17 00:00:00 2001 From: woodser Date: Fri, 27 Dec 2024 08:09:54 -0500 Subject: [PATCH 1/2] backup wallet files before saving --- .../main/java/haveno/core/xmr/wallet/XmrWalletService.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/src/main/java/haveno/core/xmr/wallet/XmrWalletService.java b/core/src/main/java/haveno/core/xmr/wallet/XmrWalletService.java index fe085de1bb..89b744ccb3 100644 --- a/core/src/main/java/haveno/core/xmr/wallet/XmrWalletService.java +++ b/core/src/main/java/haveno/core/xmr/wallet/XmrWalletService.java @@ -376,8 +376,8 @@ public void saveWallet(MoneroWallet wallet) { } public void saveWallet(MoneroWallet wallet, boolean backup) { - wallet.save(); if (backup) backupWallet(getWalletName(wallet.getPath())); + wallet.save(); } public void closeWallet(MoneroWallet wallet, boolean save) { @@ -385,8 +385,8 @@ public void closeWallet(MoneroWallet wallet, boolean save) { MoneroError err = null; String path = wallet.getPath(); try { - wallet.close(save); - if (save) backupWallet(getWalletName(path)); + if (save) saveWallet(wallet, true); + wallet.close(); } catch (MoneroError e) { err = e; } From 9891ec8c04d03200474059b170eaca32a68551ab Mon Sep 17 00:00:00 2001 From: woodser Date: Fri, 27 Dec 2024 10:17:18 -0500 Subject: [PATCH 2/2] save and backup wallet files once per 5 minutes on polling --- .../main/java/haveno/core/trade/Trade.java | 4 ++- .../haveno/core/xmr/wallet/XmrWalletBase.java | 19 ++++++++++- .../core/xmr/wallet/XmrWalletService.java | 32 +++++++++++-------- 3 files changed, 39 insertions(+), 16 deletions(-) diff --git a/core/src/main/java/haveno/core/trade/Trade.java b/core/src/main/java/haveno/core/trade/Trade.java index c5698a61c3..069b257dd5 100644 --- a/core/src/main/java/haveno/core/trade/Trade.java +++ b/core/src/main/java/haveno/core/trade/Trade.java @@ -901,6 +901,7 @@ public void changeWalletPassword(String oldPassword, String newPassword) { } } + @Override public void requestSaveWallet() { // save wallet off main thread @@ -911,6 +912,7 @@ public void requestSaveWallet() { }, getId()); } + @Override public void saveWallet() { synchronized (walletLock) { if (!walletExists()) { @@ -2675,7 +2677,7 @@ else if (hasFailedTx && isPayoutPublished()) { pollInProgress = false; } } - requestSaveWallet(); + saveWalletWithDelay(); } } diff --git a/core/src/main/java/haveno/core/xmr/wallet/XmrWalletBase.java b/core/src/main/java/haveno/core/xmr/wallet/XmrWalletBase.java index 06f2e17112..3f4ba3aa03 100644 --- a/core/src/main/java/haveno/core/xmr/wallet/XmrWalletBase.java +++ b/core/src/main/java/haveno/core/xmr/wallet/XmrWalletBase.java @@ -30,11 +30,13 @@ public abstract class XmrWalletBase { // constants public static final int SYNC_PROGRESS_TIMEOUT_SECONDS = 120; public static final int DIRECT_SYNC_WITHIN_BLOCKS = 100; + public static final int SAVE_WALLET_DELAY_SECONDS = 300; // inherited protected MoneroWallet wallet; @Getter protected final Object walletLock = new Object(); + protected Timer saveWalletDelayTimer; @Getter protected XmrConnectionService xmrConnectionService; protected boolean wasWalletSynced; @@ -146,8 +148,23 @@ public boolean requestSwitchToNextBestConnection(MoneroRpcConnection sourceConne return false; } + public void saveWalletWithDelay() { + // delay writing to disk to avoid frequent write operations + if (saveWalletDelayTimer == null) { + saveWalletDelayTimer = UserThread.runAfter(() -> { + requestSaveWallet(); + UserThread.execute(() -> saveWalletDelayTimer = null); + }, SAVE_WALLET_DELAY_SECONDS, TimeUnit.SECONDS); + } + } + + // --------------------------------- ABSTRACT ----------------------------- + + public abstract void saveWallet(); + + public abstract void requestSaveWallet(); + protected abstract void onConnectionChanged(MoneroRpcConnection connection); - // ------------------------------ PRIVATE HELPERS ------------------------- diff --git a/core/src/main/java/haveno/core/xmr/wallet/XmrWalletService.java b/core/src/main/java/haveno/core/xmr/wallet/XmrWalletService.java index 89b744ccb3..3bf8cfdeb1 100644 --- a/core/src/main/java/haveno/core/xmr/wallet/XmrWalletService.java +++ b/core/src/main/java/haveno/core/xmr/wallet/XmrWalletService.java @@ -245,16 +245,20 @@ public long getWalletCreationDate() { return user.getWalletCreationDate(); } - public void saveMainWallet() { - saveMainWallet(!(Utilities.isWindows() && wallet != null)); + @Override + public void saveWallet() { + saveWallet(!(Utilities.isWindows() && wallet != null)); } - public void saveMainWallet(boolean backup) { - saveWallet(getWallet(), backup); + public void saveWallet(boolean backup) { + synchronized (walletLock) { + saveWallet(getWallet(), backup); + } } - public void requestSaveMainWallet() { - ThreadUtils.submitToPool(() -> saveMainWallet()); // save wallet off main thread + @Override + public void requestSaveWallet() { + ThreadUtils.submitToPool(() -> saveWallet()); // save wallet off main thread } public boolean isWalletAvailable() { @@ -443,7 +447,7 @@ public MoneroTxWallet createTx(MoneroTxConfig txConfig) { if (Boolean.TRUE.equals(txConfig.getRelay())) { cachedTxs.addFirst(tx); cacheWalletInfo(); - requestSaveMainWallet(); + requestSaveWallet(); } return tx; } @@ -453,7 +457,7 @@ public MoneroTxWallet createTx(MoneroTxConfig txConfig) { public String relayTx(String metadata) { synchronized (walletLock) { String txId = wallet.relayTx(metadata); - requestSaveMainWallet(); + requestSaveWallet(); return txId; } } @@ -552,7 +556,7 @@ public void freezeOutputs(Collection keyImages) { // freeze outputs for (String keyImage : unfrozenKeyImages) wallet.freezeOutput(keyImage); cacheWalletInfo(); - requestSaveMainWallet(); + requestSaveWallet(); } } @@ -574,7 +578,7 @@ public void thawOutputs(Collection keyImages) { // thaw outputs for (String keyImage : frozenKeyImages) wallet.thawOutput(keyImage); cacheWalletInfo(); - requestSaveMainWallet(); + requestSaveWallet(); } } @@ -1424,14 +1428,14 @@ private void doMaybeInitMainWallet(boolean sync, int numSyncAttempts) { HavenoUtils.havenoSetup.getWalletInitialized().set(true); // save but skip backup on initialization - saveMainWallet(false); + saveWallet(false); } catch (Exception e) { if (isClosingWallet || isShutDownStarted || HavenoUtils.havenoSetup.getWalletInitialized().get()) return; // ignore if wallet closing, shut down started, or app already initialized log.warn("Error initially syncing main wallet: {}", e.getMessage()); if (numSyncAttempts <= 1) { log.warn("Failed to sync main wallet. Opening app without syncing", numSyncAttempts); HavenoUtils.havenoSetup.getWalletInitialized().set(true); - saveMainWallet(false); + saveWallet(false); // reschedule to init main wallet UserThread.runAfter(() -> { @@ -1809,7 +1813,7 @@ private void changeWalletPasswords(String oldPassword, String newPassword) { tasks.add(() -> { try { wallet.changePassword(oldPassword, newPassword); - saveMainWallet(); + saveWallet(); } catch (Exception e) { log.warn("Error changing main wallet password: " + e.getMessage() + "\n", e); throw e; @@ -2002,7 +2006,7 @@ else if (isWalletConnectedToDaemon()) { if (wallet != null && !isShutDownStarted) { try { cacheWalletInfo(); - requestSaveMainWallet(); + saveWalletWithDelay(); } catch (Exception e) { log.warn("Error caching wallet info: " + e.getMessage() + "\n", e); }