Skip to content

Commit a8e76fd

Browse files
committed
automatically restore backup cache if corrupt
1 parent 2d0f200 commit a8e76fd

File tree

2 files changed

+111
-11
lines changed

2 files changed

+111
-11
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: 93 additions & 9 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<>();
@@ -181,7 +180,6 @@ public class XmrWalletService extends XmrWalletBase {
181180
this.walletDir = walletDir;
182181
this.rpcBindPort = rpcBindPort;
183182
this.useNativeXmrWallet = useNativeXmrWallet;
184-
this.xmrWalletFile = new File(walletDir, MONERO_WALLET_NAME);
185183
HavenoUtils.xmrWalletService = this;
186184
HavenoUtils.xmrConnectionService = xmrConnectionService;
187185
this.xmrConnectionService = xmrConnectionService; // TODO: super's is null unless set here from injection
@@ -1327,7 +1325,7 @@ private void doMaybeInitMainWallet(boolean sync, int numAttempts) {
13271325
if (wallet == null) {
13281326
MoneroDaemonRpc daemon = xmrConnectionService.getDaemon();
13291327
log.info("Initializing main wallet with monerod=" + (daemon == null ? "null" : daemon.getRpcConnection().getUri()));
1330-
if (MoneroUtils.walletExists(xmrWalletFile.getPath())) {
1328+
if (walletExists(MONERO_WALLET_NAME)) {
13311329
wallet = openWallet(MONERO_WALLET_NAME, rpcBindPort, isProxyApplied(wasWalletSynced));
13321330
} else if (Boolean.TRUE.equals(xmrConnectionService.isConnected())) {
13331331
wallet = createWallet(MONERO_WALLET_NAME, rpcBindPort);
@@ -1475,11 +1473,54 @@ private MoneroWalletFull openWalletFull(MoneroWalletConfig config, boolean apply
14751473
MoneroRpcConnection connection = new MoneroRpcConnection(xmrConnectionService.getConnection());
14761474
if (!applyProxyUri) connection.setProxyUri(null);
14771475

1478-
// open wallet
1476+
// try opening wallet
14791477
config.setNetworkType(getMoneroNetworkType());
14801478
config.setServer(connection);
14811479
log.info("Opening full wallet " + config.getPath() + " with monerod=" + connection.getUri() + ", proxyUri=" + connection.getProxyUri());
1482-
walletFull = MoneroWalletFull.openWallet(config);
1480+
try {
1481+
walletFull = MoneroWalletFull.openWallet(config);
1482+
} catch (Exception e) {
1483+
log.warn("Failed to open full wallet '{}', attempting to use backup cache, error={}", config.getPath(), e.getMessage());
1484+
boolean retrySuccessful = false;
1485+
try {
1486+
1487+
// rename wallet cache to backup
1488+
String cachePath = walletDir.toString() + File.separator + MONERO_WALLET_NAME;
1489+
File originalCacheFile = new File(cachePath);
1490+
if (originalCacheFile.exists()) originalCacheFile.renameTo(new File(cachePath + ".backup"));
1491+
1492+
// copy latest wallet cache backup to main folder
1493+
File backupCacheFile = FileUtil.getLatestBackupFile(walletDir, MONERO_WALLET_NAME);
1494+
if (backupCacheFile != null) FileUtil.copyFile(backupCacheFile, new File(cachePath));
1495+
1496+
// retry opening wallet without original cache
1497+
try {
1498+
walletFull = MoneroWalletFull.openWallet(config);
1499+
log.info("Successfully opened full wallet using backup cache");
1500+
retrySuccessful = true;
1501+
} catch (Exception e2) {
1502+
// ignore
1503+
}
1504+
1505+
// handle success or failure
1506+
if (retrySuccessful) {
1507+
originalCacheFile.delete(); // delete original wallet cache backup
1508+
} else {
1509+
1510+
// restore original wallet cache
1511+
log.warn("Failed to open full wallet using backup cache, restoring original cache");
1512+
File cacheFile = new File(cachePath);
1513+
if (cacheFile.exists()) cacheFile.delete();
1514+
File originalCacheBackup = new File(cachePath + ".backup");
1515+
if (originalCacheBackup.exists()) originalCacheBackup.renameTo(new File(cachePath));
1516+
1517+
// throw exception
1518+
throw e;
1519+
}
1520+
} catch (Exception e2) {
1521+
throw e; // throw original exception
1522+
}
1523+
}
14831524
if (walletFull.getDaemonConnection() != null) walletFull.getDaemonConnection().setPrintStackTrace(PRINT_RPC_STACK_TRACE);
14841525
log.info("Done opening full wallet " + config.getPath());
14851526
return walletFull;
@@ -1518,7 +1559,7 @@ private MoneroWalletRpc createWalletRpc(MoneroWalletConfig config, Integer port)
15181559
} catch (Exception e) {
15191560
e.printStackTrace();
15201561
if (walletRpc != null) forceCloseWallet(walletRpc, config.getPath());
1521-
throw new IllegalStateException("Could not create wallet '" + config.getPath() + "'. Please close Haveno, stop all monero-wallet-rpc processes, and restart Haveno.");
1562+
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.");
15221563
}
15231564
}
15241565

@@ -1537,17 +1578,60 @@ private MoneroWalletRpc openWalletRpc(MoneroWalletConfig config, Integer port, b
15371578
MoneroRpcConnection connection = new MoneroRpcConnection(xmrConnectionService.getConnection());
15381579
if (!applyProxyUri) connection.setProxyUri(null);
15391580

1540-
// open wallet
1581+
// try opening wallet
15411582
log.info("Opening RPC wallet " + config.getPath() + " with monerod=" + connection.getUri() + ", proxyUri=" + connection.getProxyUri());
15421583
config.setServer(connection);
1543-
walletRpc.openWallet(config);
1584+
try {
1585+
walletRpc.openWallet(config);
1586+
} catch (Exception e) {
1587+
log.warn("Failed to open RPC wallet '{}', attempting to use backup cache, error={}", config.getPath(), e.getMessage());
1588+
boolean retrySuccessful = false;
1589+
try {
1590+
1591+
// rename wallet cache to backup
1592+
String cachePath = walletDir.toString() + File.separator + MONERO_WALLET_NAME;
1593+
File originalCacheFile = new File(cachePath);
1594+
if (originalCacheFile.exists()) originalCacheFile.renameTo(new File(cachePath + ".backup"));
1595+
1596+
// copy latest wallet cache backup to main folder
1597+
File backupCacheFile = FileUtil.getLatestBackupFile(walletDir, MONERO_WALLET_NAME);
1598+
if (backupCacheFile != null) FileUtil.copyFile(backupCacheFile, new File(cachePath));
1599+
1600+
// retry opening wallet without original cache
1601+
try {
1602+
walletRpc.openWallet(config);
1603+
log.info("Successfully opened RPC wallet using backup cache");
1604+
retrySuccessful = true;
1605+
} catch (Exception e2) {
1606+
// ignore
1607+
}
1608+
1609+
// handle success or failure
1610+
if (retrySuccessful) {
1611+
originalCacheFile.delete(); // delete original wallet cache backup
1612+
} else {
1613+
1614+
// restore original wallet cache
1615+
log.warn("Failed to open RPC wallet using backup cache, restoring original cache");
1616+
File cacheFile = new File(cachePath);
1617+
if (cacheFile.exists()) cacheFile.delete();
1618+
File originalCacheBackup = new File(cachePath + ".backup");
1619+
if (originalCacheBackup.exists()) originalCacheBackup.renameTo(new File(cachePath));
1620+
1621+
// throw exception
1622+
throw e;
1623+
}
1624+
} catch (Exception e2) {
1625+
throw e; // throw original exception
1626+
}
1627+
}
15441628
if (walletRpc.getDaemonConnection() != null) walletRpc.getDaemonConnection().setPrintStackTrace(PRINT_RPC_STACK_TRACE);
15451629
log.info("Done opening RPC wallet " + config.getPath());
15461630
return walletRpc;
15471631
} catch (Exception e) {
15481632
e.printStackTrace();
15491633
if (walletRpc != null) forceCloseWallet(walletRpc, config.getPath());
1550-
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());
1634+
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());
15511635
}
15521636
}
15531637

0 commit comments

Comments
 (0)