From 38bbfafcbb33a4a98a170383d244c60198452fc7 Mon Sep 17 00:00:00 2001 From: woodser Date: Fri, 1 Dec 2023 11:59:36 -0500 Subject: [PATCH] show wallet sync progress on startup --- .../haveno/core/api/XmrConnectionService.java | 12 ++++--- .../java/haveno/core/app/WalletAppSetup.java | 32 +++++++++++------ .../core/xmr/wallet/XmrWalletService.java | 36 ++++++++++++++++--- .../java/haveno/desktop/main/MainView.java | 6 ++-- 4 files changed, 65 insertions(+), 21 deletions(-) diff --git a/core/src/main/java/haveno/core/api/XmrConnectionService.java b/core/src/main/java/haveno/core/api/XmrConnectionService.java index 6e585464..161d63ce 100644 --- a/core/src/main/java/haveno/core/api/XmrConnectionService.java +++ b/core/src/main/java/haveno/core/api/XmrConnectionService.java @@ -250,6 +250,10 @@ public final class XmrConnectionService { return isConnectionLocal(getConnection()); } + public boolean isConnectionTor() { + return useTorProxy(getConnection()); + } + public long getRefreshPeriodMs() { return connectionList.getRefreshPeriod() > 0 ? connectionList.getRefreshPeriod() : getDefaultRefreshPeriodMs(); } @@ -318,14 +322,14 @@ public final class XmrConnectionService { if (isConnectionLocal(connection)) { if (lastInfo != null && (lastInfo.isBusySyncing() || (lastInfo.getHeightWithoutBootstrap() != null && lastInfo.getHeightWithoutBootstrap() > 0 && lastInfo.getHeightWithoutBootstrap() < lastInfo.getHeight()))) return REFRESH_PERIOD_HTTP_MS; // refresh slower if syncing or bootstrapped else return XmrLocalNode.REFRESH_PERIOD_LOCAL_MS; // TODO: announce faster refresh after done syncing - } else if (useProxy(connection)) { + } else if (useTorProxy(connection)) { return REFRESH_PERIOD_ONION_MS; } else { return REFRESH_PERIOD_HTTP_MS; } } - private boolean useProxy(MoneroRpcConnection connection) { + private boolean useTorProxy(MoneroRpcConnection connection) { return connection.isOnion() || (preferences.getUseTorForXmr().isUseTorForXmr() && !HavenoUtils.isLocalHost(connection.getUri())); } @@ -435,7 +439,7 @@ public final class XmrConnectionService { // set connection proxies log.info("TOR proxy URI: " + getProxyUri()); for (MoneroRpcConnection connection : connectionManager.getConnections()) { - if (useProxy(connection)) connection.setProxyUri(getProxyUri()); + if (useTorProxy(connection)) connection.setProxyUri(getProxyUri()); } // restore auto switch @@ -456,7 +460,7 @@ public final class XmrConnectionService { // set connection from startup argument if given connectionManager.setAutoSwitch(false); MoneroRpcConnection connection = new MoneroRpcConnection(config.xmrNode, config.xmrNodeUsername, config.xmrNodePassword).setPriority(1); - if (useProxy(connection)) connection.setProxyUri(getProxyUri()); + if (useTorProxy(connection)) connection.setProxyUri(getProxyUri()); connectionManager.setConnection(connection); // start local node if used last and offline diff --git a/core/src/main/java/haveno/core/app/WalletAppSetup.java b/core/src/main/java/haveno/core/app/WalletAppSetup.java index aa7244cb..992b25ca 100644 --- a/core/src/main/java/haveno/core/app/WalletAppSetup.java +++ b/core/src/main/java/haveno/core/app/WalletAppSetup.java @@ -125,15 +125,14 @@ public class WalletAppSetup { Long bestWalletHeight = walletHeight == null ? null : (Long) walletHeight; String walletHeightAsString = bestWalletHeight != null && bestWalletHeight > 0 ? String.valueOf(bestWalletHeight) : ""; if (walletDownloadPercentageD == 1) { - String synchronizedWith = Res.get("mainView.footer.xmrInfo.synchronizedWalletWith", getXmrNetworkAsString(), walletHeightAsString); + String synchronizedWith = Res.get("mainView.footer.xmrInfo.synchronizedWalletWith", getXmrWalletNetworkAsString(), walletHeightAsString); String feeInfo = ""; // TODO: feeService.isFeeAvailable() returns true, disable result = Res.get("mainView.footer.xmrInfo", synchronizedWith, feeInfo); getXmrSplashSyncIconId().set("image-connection-synced"); downloadCompleteHandler.run(); } else if (walletDownloadPercentageD > 0) { - result = "Synchronizing wallet ..."; // TODO: support wallet progress updates and use below translation - // String synchronizingWith = Res.get("mainView.footer.xmrInfo.synchronizingWalletWith", getXmrNetworkAsString(), walletHeightAsString, FormattingUtils.formatToRoundedPercentWithSymbol(walletDownloadPercentageD)); - // result = Res.get("mainView.footer.xmrInfo", synchronizingWith, ""); + String synchronizingWith = Res.get("mainView.footer.xmrInfo.synchronizingWalletWith", getXmrWalletNetworkAsString(), walletHeightAsString, FormattingUtils.formatToRoundedPercentWithSymbol(walletDownloadPercentageD)); + result = Res.get("mainView.footer.xmrInfo", synchronizingWith, ""); getXmrSplashSyncIconId().set(""); // clear synced icon } else { @@ -143,23 +142,23 @@ public class WalletAppSetup { Long bestChainHeight = chainHeight == null ? null : (Long) chainHeight; String chainHeightAsString = bestChainHeight != null && bestChainHeight > 0 ? String.valueOf(bestChainHeight) : ""; if (chainDownloadPercentageD == 1) { - String synchronizedWith = Res.get("mainView.footer.xmrInfo.synchronizedDaemonWith", getXmrNetworkAsString(), chainHeightAsString); + String synchronizedWith = Res.get("mainView.footer.xmrInfo.synchronizedDaemonWith", getXmrDaemonNetworkAsString(), chainHeightAsString); String feeInfo = ""; // TODO: feeService.isFeeAvailable() returns true, disable result = Res.get("mainView.footer.xmrInfo", synchronizedWith, feeInfo); getXmrSplashSyncIconId().set("image-connection-synced"); } else if (chainDownloadPercentageD > 0.0) { - String synchronizingWith = Res.get("mainView.footer.xmrInfo.synchronizingDaemonWith", getXmrNetworkAsString(), chainHeightAsString, FormattingUtils.formatToRoundedPercentWithSymbol(chainDownloadPercentageD)); + String synchronizingWith = Res.get("mainView.footer.xmrInfo.synchronizingDaemonWith", getXmrDaemonNetworkAsString(), chainHeightAsString, FormattingUtils.formatToRoundedPercentWithSymbol(chainDownloadPercentageD)); result = Res.get("mainView.footer.xmrInfo", synchronizingWith, ""); } else { result = Res.get("mainView.footer.xmrInfo", Res.get("mainView.footer.xmrInfo.connectingTo"), - getXmrNetworkAsString()); + getXmrDaemonNetworkAsString()); } } } else { result = Res.get("mainView.footer.xmrInfo", Res.get("mainView.footer.xmrInfo.connectionFailed"), - getXmrNetworkAsString()); + getXmrDaemonNetworkAsString()); if (exception != null) { if (exception instanceof TimeoutException) { getWalletServiceErrorMsg().set(Res.get("mainView.walletServiceErrorMsg.timeout")); @@ -253,11 +252,22 @@ public class WalletAppSetup { }); } - private String getXmrNetworkAsString() { + private String getXmrDaemonNetworkAsString() { String postFix; - if (config.ignoreLocalXmrNode) + if (xmrConnectionService.isConnectionLocal()) postFix = " " + Res.get("mainView.footer.localhostMoneroNode"); - else if (preferences.getUseTorForXmr().isUseTorForXmr()) + else if (xmrConnectionService.isConnectionTor()) + postFix = " " + Res.get("mainView.footer.usingTor"); + else + postFix = ""; + return Res.get(config.baseCurrencyNetwork.name()) + postFix; + } + + private String getXmrWalletNetworkAsString() { + String postFix; + if (xmrConnectionService.isConnectionLocal()) + postFix = " " + Res.get("mainView.footer.localhostMoneroNode"); + else if (xmrWalletService.isProxyApplied()) postFix = " " + Res.get("mainView.footer.usingTor"); else postFix = ""; 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 335a8676..05c88671 100644 --- a/core/src/main/java/haveno/core/xmr/wallet/XmrWalletService.java +++ b/core/src/main/java/haveno/core/xmr/wallet/XmrWalletService.java @@ -28,6 +28,7 @@ import monero.common.MoneroError; import monero.common.MoneroRpcConnection; import monero.common.MoneroRpcError; import monero.common.MoneroUtils; +import monero.common.TaskLooper; import monero.daemon.MoneroDaemonRpc; import monero.daemon.model.MoneroFeeEstimate; import monero.daemon.model.MoneroNetworkType; @@ -126,6 +127,7 @@ public class XmrWalletService { private boolean isShutDownStarted = false; private ExecutorService syncWalletThreadPool = Executors.newFixedThreadPool(10); // TODO: adjust based on connection type private Long syncStartHeight = null; + private TaskLooper syncLooper = null; @Inject XmrWalletService(Preferences preferences, @@ -247,6 +249,10 @@ public class XmrWalletService { public XmrConnectionService getConnectionService() { return xmrConnectionService; } + + public boolean isProxyApplied() { + return isProxyApplied(wasWalletSynced); + } public boolean isProxyApplied(boolean wasWalletSynced) { return preferences.isProxyApplied(wasWalletSynced); @@ -728,11 +734,8 @@ public class XmrWalletService { // sync main wallet log.info("Syncing main wallet"); - updateSyncProgress(); long time = System.currentTimeMillis(); - wallet.sync(); // blocking - walletHeight.set(wallet.getHeight()); - wasWalletSynced = true; + syncWalletWithProgress(); // blocking log.info("Done syncing main wallet in " + (System.currentTimeMillis() - time) + " ms"); wallet.startSyncing(xmrConnectionService.getRefreshPeriodMs()); wallet.getTxs(new MoneroTxQuery().setIsLocked(true)); // TODO: main wallet's balance does update on startup with 0 conf PaymentReceivedMessage until pool txs fetched? @@ -777,8 +780,33 @@ public class XmrWalletService { } } + private void syncWalletWithProgress() { + updateSyncProgress(); + wallet.startSyncing(); + CountDownLatch latch = new CountDownLatch(1); + syncLooper = new TaskLooper(() -> { + if (wallet.getHeight() < xmrConnectionService.getTargetHeight()) updateSyncProgress(); + else { + wasWalletSynced = true; + updateSyncProgress(); + syncLooper.stop(); + latch.countDown(); + } + }); + syncLooper.start(1000); + HavenoUtils.awaitLatch(latch); + } + private void updateSyncProgress() { walletHeight.set(wallet.getHeight()); + + // new wallet reports height 1 before synced + if (wallet.getHeight() == 1) { + downloadListener.progress(.0001, xmrConnectionService.getTargetHeight(), null); // >0% shows progress bar + return; + } + + // set progress long targetHeight = xmrConnectionService.getTargetHeight(); long blocksLeft = targetHeight - walletHeight.get(); if (syncStartHeight == null) syncStartHeight = walletHeight.get(); diff --git a/desktop/src/main/java/haveno/desktop/main/MainView.java b/desktop/src/main/java/haveno/desktop/main/MainView.java index 3cda75ca..fe64223a 100644 --- a/desktop/src/main/java/haveno/desktop/main/MainView.java +++ b/desktop/src/main/java/haveno/desktop/main/MainView.java @@ -536,8 +536,10 @@ public class MainView extends InitializableView { xmrSyncIcon.setVisible(true); xmrSyncIcon.setManaged(true); - xmrSyncIndicator.setVisible(false); - xmrSyncIndicator.setManaged(false); + // show progress bar until we have checkmark id + boolean inProgress = "".equals(newValue); + xmrSyncIndicator.setVisible(inProgress); + xmrSyncIndicator.setManaged(inProgress); }; model.getXmrSplashSyncIconId().addListener(xmrSyncIconIdListener);