Skip to content

Commit fb53037

Browse files
committed
automatically restore backup cache if corrupt
1 parent 30f0cf2 commit fb53037

File tree

2 files changed

+66
-9
lines changed

2 files changed

+66
-9
lines changed

common/src/main/java/haveno/common/file/FileUtil.java

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,13 @@
4040

4141
@Slf4j
4242
public class FileUtil {
43+
44+
private static final String BACKUP_DIR = "backup";
45+
4346
public static void rollingBackup(File dir, String fileName, int numMaxBackupFiles) {
4447
if (numMaxBackupFiles <= 0) return;
4548
if (dir.exists()) {
46-
File backupDir = new File(Paths.get(dir.getAbsolutePath(), "backup").toString());
49+
File backupDir = new File(Paths.get(dir.getAbsolutePath(), BACKUP_DIR).toString());
4750
if (!backupDir.exists())
4851
if (!backupDir.mkdir())
4952
log.warn("make dir failed.\nBackupDir=" + backupDir.getAbsolutePath());
@@ -72,8 +75,21 @@ public static void rollingBackup(File dir, String fileName, int numMaxBackupFile
7275
}
7376
}
7477

78+
public static File getLatestBackupFile(File dir, String fileName) {
79+
File backupDir = new File(Paths.get(dir.getAbsolutePath(), BACKUP_DIR).toString());
80+
if (!backupDir.exists()) return null;
81+
String dirName = "backups_" + fileName;
82+
if (dirName.contains(".")) dirName = dirName.replace(".", "_");
83+
File backupFileDir = new File(Paths.get(backupDir.getAbsolutePath(), dirName).toString());
84+
if (!backupFileDir.exists()) return null;
85+
File[] files = backupFileDir.listFiles();
86+
if (files == null || files.length == 0) return null;
87+
Arrays.sort(files, Comparator.comparing(File::getName));
88+
return files[files.length - 1];
89+
}
90+
7591
public static void deleteRollingBackup(File dir, String fileName) {
76-
File backupDir = new File(Paths.get(dir.getAbsolutePath(), "backup").toString());
92+
File backupDir = new File(Paths.get(dir.getAbsolutePath(), BACKUP_DIR).toString());
7793
if (!backupDir.exists()) return;
7894
String dirName = "backups_" + fileName;
7995
if (dirName.contains(".")) dirName = dirName.replace(".", "_");

core/src/main/java/haveno/core/xmr/wallet/XmrWalletService.java

Lines changed: 48 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,6 @@ public class XmrWalletService extends XmrWalletBase {
136136
private final WalletsSetup walletsSetup;
137137

138138
private final File walletDir;
139-
private final File xmrWalletFile;
140139
private final int rpcBindPort;
141140
private final boolean useNativeXmrWallet;
142141
protected final CopyOnWriteArraySet<XmrBalanceListener> balanceListeners = new CopyOnWriteArraySet<>();
@@ -180,7 +179,6 @@ public class XmrWalletService extends XmrWalletBase {
180179
this.walletDir = walletDir;
181180
this.rpcBindPort = rpcBindPort;
182181
this.useNativeXmrWallet = useNativeXmrWallet;
183-
this.xmrWalletFile = new File(walletDir, MONERO_WALLET_NAME);
184182
HavenoUtils.xmrWalletService = this;
185183
HavenoUtils.xmrConnectionService = xmrConnectionService;
186184
this.xmrConnectionService = xmrConnectionService; // TODO: super's is null unless set here from injection
@@ -1326,7 +1324,7 @@ private void doMaybeInitMainWallet(boolean sync, int numAttempts) {
13261324
if (wallet == null) {
13271325
MoneroDaemonRpc daemon = xmrConnectionService.getDaemon();
13281326
log.info("Initializing main wallet with monerod=" + (daemon == null ? "null" : daemon.getRpcConnection().getUri()));
1329-
if (MoneroUtils.walletExists(xmrWalletFile.getPath())) {
1327+
if (walletExists(MONERO_WALLET_NAME)) {
13301328
wallet = openWallet(MONERO_WALLET_NAME, rpcBindPort, isProxyApplied(wasWalletSynced));
13311329
} else if (Boolean.TRUE.equals(xmrConnectionService.isConnected())) {
13321330
wallet = createWallet(MONERO_WALLET_NAME, rpcBindPort);
@@ -1517,7 +1515,7 @@ private MoneroWalletRpc createWalletRpc(MoneroWalletConfig config, Integer port)
15171515
} catch (Exception e) {
15181516
e.printStackTrace();
15191517
if (walletRpc != null) forceCloseWallet(walletRpc, config.getPath());
1520-
throw new IllegalStateException("Could not create wallet '" + config.getPath() + "'. Please close Haveno, stop all monero-wallet-rpc processes, and restart Haveno.");
1518+
throw new IllegalStateException("Could not create wallet '" + config.getPath() + "'. Please close Haveno, stop all monero-wallet-rpc processes in your task manager, and restart Haveno.");
15211519
}
15221520
}
15231521

@@ -1536,17 +1534,60 @@ private MoneroWalletRpc openWalletRpc(MoneroWalletConfig config, Integer port, b
15361534
MoneroRpcConnection connection = new MoneroRpcConnection(xmrConnectionService.getConnection());
15371535
if (!applyProxyUri) connection.setProxyUri(null);
15381536

1539-
// open wallet
1537+
// try opening wallet
15401538
log.info("Opening RPC wallet " + config.getPath() + " with monerod=" + connection.getUri() + ", proxyUri=" + connection.getProxyUri());
15411539
config.setServer(connection);
1542-
walletRpc.openWallet(config);
1540+
try {
1541+
walletRpc.openWallet(config);
1542+
} catch (Exception e) {
1543+
log.warn("Failed to open RPC wallet '{}', attempting to use backup cache, error={}", config.getPath(), e.getMessage());
1544+
boolean retrySuccessful = false;
1545+
try {
1546+
1547+
// rename wallet cache to backup
1548+
String cachePath = walletDir.toString() + File.separator + MONERO_WALLET_NAME;
1549+
File originalCacheFile = new File(cachePath);
1550+
if (originalCacheFile.exists()) originalCacheFile.renameTo(new File(cachePath + ".backup"));
1551+
1552+
// copy latest wallet cache backup to main folder
1553+
File backupCacheFile = FileUtil.getLatestBackupFile(walletDir, MONERO_WALLET_NAME);
1554+
if (backupCacheFile != null) FileUtil.copyFile(backupCacheFile, new File(cachePath));
1555+
1556+
// retry opening wallet without original cache
1557+
try {
1558+
walletRpc.openWallet(config);
1559+
log.info("Successfully opened RPC wallet using backup cache");
1560+
retrySuccessful = true;
1561+
} catch (Exception e2) {
1562+
// ignore
1563+
}
1564+
1565+
// handle success or failure
1566+
if (retrySuccessful) {
1567+
originalCacheFile.delete(); // delete original wallet cache backup
1568+
} else {
1569+
1570+
// restore original wallet cache
1571+
log.warn("Failed to open RPC wallet using backup cache, restoring original cache");
1572+
File cacheFile = new File(cachePath);
1573+
if (cacheFile.exists()) cacheFile.delete();
1574+
File originalCacheBackup = new File(cachePath + ".backup");
1575+
if (originalCacheBackup.exists()) originalCacheBackup.renameTo(new File(cachePath));
1576+
1577+
// throw exception
1578+
throw e;
1579+
}
1580+
} catch (Exception e2) {
1581+
throw e; // throw original exception
1582+
}
1583+
}
15431584
if (walletRpc.getDaemonConnection() != null) walletRpc.getDaemonConnection().setPrintStackTrace(PRINT_RPC_STACK_TRACE);
15441585
log.info("Done opening RPC wallet " + config.getPath());
15451586
return walletRpc;
15461587
} catch (Exception e) {
15471588
e.printStackTrace();
15481589
if (walletRpc != null) forceCloseWallet(walletRpc, config.getPath());
1549-
throw new IllegalStateException("Could not open wallet '" + config.getPath() + "'. Please close Haveno, stop all monero-wallet-rpc processes, and restart Haveno.\n\nError message: " + e.getMessage());
1590+
throw new IllegalStateException("Could not open wallet '" + config.getPath() + "'. Please close Haveno, stop all monero-wallet-rpc processes in your task manager, and restart Haveno.\n\nError message: " + e.getMessage());
15501591
}
15511592
}
15521593

0 commit comments

Comments
 (0)