From d094997666fc0b79d09b7802ae01f9527676cdd4 Mon Sep 17 00:00:00 2001 From: woodser Date: Fri, 24 Nov 2023 13:33:55 -0500 Subject: [PATCH] show daemon sync progress on startup then sync wallet --- .../api/CoreMoneroConnectionsService.java | 28 +++++++---- .../java/haveno/core/app/AppStartupState.java | 21 +++++++-- .../java/haveno/core/app/HavenoSetup.java | 2 +- .../java/haveno/core/app/WalletAppSetup.java | 20 +++++--- .../haveno/core/offer/OpenOfferManager.java | 2 + .../haveno/core/support/SupportManager.java | 7 ++- .../core/support/dispute/DisputeManager.java | 7 ++- .../support/traderchat/TraderChatManager.java | 4 +- .../main/java/haveno/core/xmr/Balances.java | 4 +- .../core/xmr/setup/DownloadListener.java | 2 +- .../haveno/core/xmr/setup/WalletConfig.java | 11 ----- .../haveno/core/xmr/setup/WalletsSetup.java | 39 +-------------- .../core/xmr/wallet/BtcWalletService.java | 4 ++ .../haveno/core/xmr/wallet/WalletService.java | 4 +- .../core/xmr/wallet/WalletsManager.java | 2 +- .../core/xmr/wallet/XmrWalletService.java | 47 +++++++++++++++---- .../offer/offerbook/OfferBookViewModel.java | 1 + 17 files changed, 119 insertions(+), 86 deletions(-) diff --git a/core/src/main/java/haveno/core/api/CoreMoneroConnectionsService.java b/core/src/main/java/haveno/core/api/CoreMoneroConnectionsService.java index 6c74ec56..09c9722d 100644 --- a/core/src/main/java/haveno/core/api/CoreMoneroConnectionsService.java +++ b/core/src/main/java/haveno/core/api/CoreMoneroConnectionsService.java @@ -2,6 +2,7 @@ package haveno.core.api; import haveno.common.UserThread; import haveno.common.app.DevEnv; +import haveno.common.config.BaseCurrencyNetwork; import haveno.common.config.Config; import haveno.core.trade.HavenoUtils; import haveno.core.user.Preferences; @@ -69,6 +70,7 @@ public final class CoreMoneroConnectionsService { private MoneroDaemonRpc daemon; @Getter private MoneroDaemonInfo lastInfo; + private Long syncStartHeight = null; private TaskLooper daemonPollLooper; private boolean isShutDownStarted; private List listeners = new ArrayList<>(); @@ -299,17 +301,12 @@ public final class CoreMoneroConnectionsService { return downloadPercentageProperty().get() == 1d; } - /** - * Signals that both the daemon and wallet have synced. - * - * TODO: separate daemon and wallet download/done listeners - */ - public void doneDownload() { + // ------------------------------- HELPERS -------------------------------- + + private void doneDownload() { downloadListener.doneDownload(); } - // ------------------------------- HELPERS -------------------------------- - private boolean isConnectionLocal(MoneroRpcConnection connection) { return connection != null && HavenoUtils.isLocalHost(connection.getUri()); } @@ -555,11 +552,26 @@ public final class CoreMoneroConnectionsService { synchronized (lock) { if (isShutDownStarted) return; try { + + // poll daemon log.debug("Polling daemon info"); if (daemon == null) throw new RuntimeException("No daemon connection"); lastInfo = daemon.getInfo(); + + // set chain height chainHeight.set(lastInfo.getHeight()); + // update sync progress + boolean isTestnet = Config.baseCurrencyNetwork() == BaseCurrencyNetwork.XMR_LOCAL; + if (lastInfo.isSynchronized() || isTestnet) doneDownload(); // TODO: skipping synchronized check for testnet because tests cannot sync 3rd local node, see "Can manage Monero daemon connections" + else if (lastInfo.isBusySyncing()) { + long targetHeight = lastInfo.getTargetHeight(); + long blocksLeft = targetHeight - lastInfo.getHeight(); + if (syncStartHeight == null) syncStartHeight = lastInfo.getHeight(); + double percent = ((double) Math.max(1, lastInfo.getHeight() - syncStartHeight) / (double) (targetHeight - syncStartHeight)) * 100d; // grant at least 1 block to show progress + downloadListener.progress(percent, blocksLeft, null); + } + // set peer connections // TODO: peers often uknown due to restricted RPC call, skipping call to get peer connections // try { diff --git a/core/src/main/java/haveno/core/app/AppStartupState.java b/core/src/main/java/haveno/core/app/AppStartupState.java index 94767beb..3f2ba574 100644 --- a/core/src/main/java/haveno/core/app/AppStartupState.java +++ b/core/src/main/java/haveno/core/app/AppStartupState.java @@ -19,6 +19,7 @@ package haveno.core.app; import haveno.core.api.CoreMoneroConnectionsService; import haveno.core.api.CoreNotificationService; +import haveno.core.xmr.wallet.XmrWalletService; import haveno.network.p2p.BootstrapListener; import haveno.network.p2p.P2PService; import javafx.beans.property.BooleanProperty; @@ -47,11 +48,13 @@ public class AppStartupState { private final BooleanProperty applicationFullyInitialized = new SimpleBooleanProperty(); private final BooleanProperty updatedDataReceived = new SimpleBooleanProperty(); private final BooleanProperty isBlockDownloadComplete = new SimpleBooleanProperty(); + private final BooleanProperty isWalletSynced = new SimpleBooleanProperty(); private final BooleanProperty hasSufficientPeersForBroadcast = new SimpleBooleanProperty(); @Inject public AppStartupState(CoreNotificationService notificationService, CoreMoneroConnectionsService connectionsService, + XmrWalletService xmrWalletService, P2PService p2PService) { p2PService.addP2PServiceListener(new BootstrapListener() { @@ -66,6 +69,11 @@ public class AppStartupState { isBlockDownloadComplete.set(true); }); + xmrWalletService.downloadPercentageProperty().addListener((observable, oldValue, newValue) -> { + if (xmrWalletService.isWalletSynced()) + isWalletSynced.set(true); + }); + connectionsService.numPeersProperty().addListener((observable, oldValue, newValue) -> { if (connectionsService.hasSufficientPeersForBroadcast()) hasSufficientPeersForBroadcast.set(true); @@ -73,14 +81,15 @@ public class AppStartupState { p2pNetworkAndWalletInitialized = EasyBind.combine(updatedDataReceived, isBlockDownloadComplete, + isWalletSynced, hasSufficientPeersForBroadcast, // TODO: consider sufficient number of peers? allDomainServicesInitialized, - (a, b, c, d) -> { - log.info("Combined initialized state = {} = updatedDataReceived={} && isBlockDownloadComplete={} && hasSufficientPeersForBroadcast={} && allDomainServicesInitialized={}", (a && b && c && d), updatedDataReceived.get(), isBlockDownloadComplete.get(), hasSufficientPeersForBroadcast.get(), allDomainServicesInitialized.get()); - if (a && b) { + (a, b, c, d, e) -> { + log.info("Combined initialized state = {} = updatedDataReceived={} && isBlockDownloadComplete={} && isWalletSynced={} && hasSufficientPeersForBroadcast={} && allDomainServicesInitialized={}", (a && b && c && d && e), updatedDataReceived.get(), isBlockDownloadComplete.get(), isWalletSynced.get(), hasSufficientPeersForBroadcast.get(), allDomainServicesInitialized.get()); + if (a && b && c) { walletAndNetworkReady.set(true); } - return a && d; // app fully initialized before daemon connection and wallet by default // TODO: rename variable + return a && e; // app fully initialized before daemon connection and wallet by default }); p2pNetworkAndWalletInitialized.subscribe((observable, oldValue, newValue) -> { if (newValue) { @@ -136,6 +145,10 @@ public class AppStartupState { return isBlockDownloadComplete.get(); } + public boolean isWalletSynced() { + return isWalletSynced.get(); + } + public ReadOnlyBooleanProperty isBlockDownloadCompleteProperty() { return isBlockDownloadComplete; } diff --git a/core/src/main/java/haveno/core/app/HavenoSetup.java b/core/src/main/java/haveno/core/app/HavenoSetup.java index 830952a8..c06d0948 100644 --- a/core/src/main/java/haveno/core/app/HavenoSetup.java +++ b/core/src/main/java/haveno/core/app/HavenoSetup.java @@ -438,7 +438,7 @@ public class HavenoSetup { revolutAccountsUpdateHandler, amazonGiftCardAccountsUpdateHandler); - if (walletsSetup.downloadPercentageProperty().get() == 1) { // TODO: update for XMR + if (xmrWalletService.downloadPercentageProperty().get() == 1) { checkForLockedUpFunds(); } diff --git a/core/src/main/java/haveno/core/app/WalletAppSetup.java b/core/src/main/java/haveno/core/app/WalletAppSetup.java index 77c07678..3b4aa907 100644 --- a/core/src/main/java/haveno/core/app/WalletAppSetup.java +++ b/core/src/main/java/haveno/core/app/WalletAppSetup.java @@ -31,6 +31,7 @@ import haveno.core.xmr.exceptions.InvalidHostException; import haveno.core.xmr.exceptions.RejectedTxException; import haveno.core.xmr.setup.WalletsSetup; import haveno.core.xmr.wallet.WalletsManager; +import haveno.core.xmr.wallet.XmrWalletService; import javafx.beans.property.DoubleProperty; import javafx.beans.property.ObjectProperty; import javafx.beans.property.SimpleDoubleProperty; @@ -39,9 +40,8 @@ import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.StringProperty; import lombok.Getter; import lombok.extern.slf4j.Slf4j; - +import monero.common.MoneroUtils; import org.bitcoinj.core.RejectMessage; -import org.bitcoinj.core.VersionMessage; import org.bitcoinj.store.BlockStoreException; import org.bitcoinj.store.ChainFileLockedException; import org.fxmisc.easybind.EasyBind; @@ -61,6 +61,7 @@ public class WalletAppSetup { private final WalletsManager walletsManager; private final WalletsSetup walletsSetup; private final CoreMoneroConnectionsService connectionService; + private final XmrWalletService xmrWalletService; private final Config config; private final Preferences preferences; @@ -85,12 +86,14 @@ public class WalletAppSetup { WalletsManager walletsManager, WalletsSetup walletsSetup, CoreMoneroConnectionsService connectionService, + XmrWalletService xmrWalletService, Config config, Preferences preferences) { this.coreContext = coreContext; this.walletsManager = walletsManager; this.walletsSetup = walletsSetup; this.connectionService = connectionService; + this.xmrWalletService = xmrWalletService; this.config = config; this.preferences = preferences; this.useTorForXmr.set(preferences.getUseTorForXmr()); @@ -101,18 +104,21 @@ public class WalletAppSetup { @Nullable Runnable showPopupIfInvalidBtcConfigHandler, Runnable downloadCompleteHandler, Runnable walletInitializedHandler) { - log.info("Initialize WalletAppSetup with BitcoinJ version {} and hash of BitcoinJ commit {}", - VersionMessage.BITCOINJ_VERSION, "2a80db4"); + log.info("Initialize WalletAppSetup with monero-java version {}", MoneroUtils.getVersion()); ObjectProperty walletServiceException = new SimpleObjectProperty<>(); - xmrInfoBinding = EasyBind.combine(connectionService.downloadPercentageProperty(), // TODO (woodser): update to XMR + xmrInfoBinding = EasyBind.combine(connectionService.downloadPercentageProperty(), connectionService.chainHeightProperty(), + xmrWalletService.downloadPercentageProperty(), + xmrWalletService.walletHeightProperty(), walletServiceException, getWalletServiceErrorMsg(), - (downloadPercentage, chainHeight, exception, errorMsg) -> { + (chainDownloadPercentage, chainHeight, walletDownloadPercentage, walletHeight, exception, errorMsg) -> { String result; if (exception == null && errorMsg == null) { - double percentage = (double) downloadPercentage; + + // TODO: update for daemon and wallet sync progress + double percentage = (double) chainDownloadPercentage; xmrSyncProgress.set(percentage); Long bestChainHeight = chainHeight == null ? null : (Long) chainHeight; String chainHeightAsString = bestChainHeight != null && bestChainHeight > 0 ? diff --git a/core/src/main/java/haveno/core/offer/OpenOfferManager.java b/core/src/main/java/haveno/core/offer/OpenOfferManager.java index 04941f56..705e87b4 100644 --- a/core/src/main/java/haveno/core/offer/OpenOfferManager.java +++ b/core/src/main/java/haveno/core/offer/OpenOfferManager.java @@ -120,8 +120,10 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe private final KeyRing keyRing; private final User user; private final P2PService p2PService; + @Getter private final CoreMoneroConnectionsService connectionsService; private final BtcWalletService btcWalletService; + @Getter private final XmrWalletService xmrWalletService; private final TradeWalletService tradeWalletService; private final OfferBookService offerBookService; diff --git a/core/src/main/java/haveno/core/support/SupportManager.java b/core/src/main/java/haveno/core/support/SupportManager.java index 783e00c6..3f05d104 100644 --- a/core/src/main/java/haveno/core/support/SupportManager.java +++ b/core/src/main/java/haveno/core/support/SupportManager.java @@ -31,6 +31,7 @@ import haveno.core.trade.Trade; import haveno.core.trade.TradeManager; import haveno.core.trade.protocol.TradeProtocol; import haveno.core.trade.protocol.TradeProtocol.MailboxMessageComparator; +import haveno.core.xmr.wallet.XmrWalletService; import haveno.network.p2p.AckMessage; import haveno.network.p2p.AckMessageSourceType; import haveno.network.p2p.DecryptedMessageWithPubKey; @@ -53,6 +54,7 @@ public abstract class SupportManager { protected final P2PService p2PService; protected final TradeManager tradeManager; protected final CoreMoneroConnectionsService connectionService; + protected final XmrWalletService xmrWalletService; protected final CoreNotificationService notificationService; protected final Map delayMsgMap = new HashMap<>(); private final Object lock = new Object(); @@ -68,10 +70,12 @@ public abstract class SupportManager { public SupportManager(P2PService p2PService, CoreMoneroConnectionsService connectionService, + XmrWalletService xmrWalletService, CoreNotificationService notificationService, TradeManager tradeManager) { this.p2PService = p2PService; this.connectionService = connectionService; + this.xmrWalletService = xmrWalletService; this.mailboxMessageService = p2PService.getMailboxMessageService(); this.notificationService = notificationService; this.tradeManager = tradeManager; @@ -333,7 +337,8 @@ public abstract class SupportManager { return allServicesInitialized && p2PService.isBootstrapped() && connectionService.isDownloadComplete() && - connectionService.hasSufficientPeersForBroadcast(); + connectionService.hasSufficientPeersForBroadcast() && + xmrWalletService.isWalletSynced(); } diff --git a/core/src/main/java/haveno/core/support/dispute/DisputeManager.java b/core/src/main/java/haveno/core/support/dispute/DisputeManager.java index 628d8845..dc461d1e 100644 --- a/core/src/main/java/haveno/core/support/dispute/DisputeManager.java +++ b/core/src/main/java/haveno/core/support/dispute/DisputeManager.java @@ -114,7 +114,7 @@ public abstract class DisputeManager> extends Sup DisputeListService disputeListService, Config config, PriceFeedService priceFeedService) { - super(p2PService, connectionService, notificationService, tradeManager); + super(p2PService, connectionService, xmrWalletService, notificationService, tradeManager); this.tradeWalletService = tradeWalletService; this.xmrWalletService = xmrWalletService; @@ -257,6 +257,11 @@ public abstract class DisputeManager> extends Sup tryApplyMessages(); }); + xmrWalletService.downloadPercentageProperty().addListener((observable, oldValue, newValue) -> { + if (xmrWalletService.isWalletSynced()) + tryApplyMessages(); + }); + connectionService.numPeersProperty().addListener((observable, oldValue, newValue) -> { if (connectionService.hasSufficientPeersForBroadcast()) tryApplyMessages(); diff --git a/core/src/main/java/haveno/core/support/traderchat/TraderChatManager.java b/core/src/main/java/haveno/core/support/traderchat/TraderChatManager.java index eea25bc6..e82d3c0c 100644 --- a/core/src/main/java/haveno/core/support/traderchat/TraderChatManager.java +++ b/core/src/main/java/haveno/core/support/traderchat/TraderChatManager.java @@ -28,6 +28,7 @@ import haveno.core.support.messages.ChatMessage; import haveno.core.support.messages.SupportMessage; import haveno.core.trade.Trade; import haveno.core.trade.TradeManager; +import haveno.core.xmr.wallet.XmrWalletService; import haveno.network.p2p.AckMessageSourceType; import haveno.network.p2p.NodeAddress; import haveno.network.p2p.P2PService; @@ -53,10 +54,11 @@ public class TraderChatManager extends SupportManager { @Inject public TraderChatManager(P2PService p2PService, CoreMoneroConnectionsService connectionService, + XmrWalletService xmrWalletService, CoreNotificationService notificationService, TradeManager tradeManager, PubKeyRingProvider pubKeyRingProvider) { - super(p2PService, connectionService, notificationService, tradeManager); + super(p2PService, connectionService, xmrWalletService, notificationService, tradeManager); this.pubKeyRingProvider = pubKeyRingProvider; } diff --git a/core/src/main/java/haveno/core/xmr/Balances.java b/core/src/main/java/haveno/core/xmr/Balances.java index 721c2c81..1e3a99e4 100644 --- a/core/src/main/java/haveno/core/xmr/Balances.java +++ b/core/src/main/java/haveno/core/xmr/Balances.java @@ -86,7 +86,7 @@ public class Balances { } private void updateBalances() { - if (!xmrWalletService.isWalletReady()) return; + if (!xmrWalletService.isWalletAvailable()) return; try { updateAvailableBalance(); updatePendingBalance(); @@ -94,7 +94,7 @@ public class Balances { updateReservedTradeBalance(); updateReservedBalance(); } catch (Exception e) { - if (xmrWalletService.isWalletReady()) throw e; // ignore exception if wallet isn't ready + if (xmrWalletService.isWalletAvailable()) throw e; // ignore exception if wallet isn't ready } } diff --git a/core/src/main/java/haveno/core/xmr/setup/DownloadListener.java b/core/src/main/java/haveno/core/xmr/setup/DownloadListener.java index ada82b00..19fc73dd 100644 --- a/core/src/main/java/haveno/core/xmr/setup/DownloadListener.java +++ b/core/src/main/java/haveno/core/xmr/setup/DownloadListener.java @@ -10,7 +10,7 @@ import java.util.Date; public class DownloadListener { private final DoubleProperty percentage = new SimpleDoubleProperty(-1); - public void progress(double percentage, int blocksLeft, Date date) { + public void progress(double percentage, long blocksLeft, Date date) { UserThread.execute(() -> this.percentage.set(percentage / 100d)); } diff --git a/core/src/main/java/haveno/core/xmr/setup/WalletConfig.java b/core/src/main/java/haveno/core/xmr/setup/WalletConfig.java index c36a6333..903c0255 100644 --- a/core/src/main/java/haveno/core/xmr/setup/WalletConfig.java +++ b/core/src/main/java/haveno/core/xmr/setup/WalletConfig.java @@ -32,7 +32,6 @@ import org.bitcoinj.core.Context; import org.bitcoinj.core.NetworkParameters; import org.bitcoinj.core.PeerAddress; import org.bitcoinj.core.PeerGroup; -import org.bitcoinj.core.listeners.DownloadProgressTracker; import org.bitcoinj.crypto.KeyCrypter; import org.bitcoinj.net.discovery.PeerDiscovery; import org.bitcoinj.script.Script; @@ -92,7 +91,6 @@ public class WalletConfig extends AbstractIdleService { protected volatile File vBtcWalletFile; protected PeerAddress[] peerAddresses; - protected DownloadListener downloadListener; protected InputStream checkpoints; protected String userAgent, version; @Nullable @@ -169,15 +167,6 @@ public class WalletConfig extends AbstractIdleService { return setPeerNodes(new PeerAddress(params, localHost, params.getPort())); } - /** - * If you want to learn about the sync process, you can provide a listener here. For instance, a - * {@link DownloadProgressTracker} is a good choice. - */ - public WalletConfig setDownloadListener(DownloadListener listener) { - this.downloadListener = listener; - return this; - } - /** * If set, the file is expected to contain a checkpoints file calculated with BuildCheckpoints. It makes initial * block sync faster for new users - please refer to the documentation on the bitcoinj website diff --git a/core/src/main/java/haveno/core/xmr/setup/WalletsSetup.java b/core/src/main/java/haveno/core/xmr/setup/WalletsSetup.java index d89f75b2..e7e8b37d 100644 --- a/core/src/main/java/haveno/core/xmr/setup/WalletsSetup.java +++ b/core/src/main/java/haveno/core/xmr/setup/WalletsSetup.java @@ -42,13 +42,7 @@ import haveno.core.xmr.nodes.XmrNodesSetupPreferences; import haveno.network.Socks5MultiDiscovery; import haveno.network.Socks5ProxyProvider; import javafx.beans.property.BooleanProperty; -import javafx.beans.property.IntegerProperty; -import javafx.beans.property.LongProperty; -import javafx.beans.property.ReadOnlyDoubleProperty; -import javafx.beans.property.ReadOnlyIntegerProperty; import javafx.beans.property.SimpleBooleanProperty; -import javafx.beans.property.SimpleIntegerProperty; -import javafx.beans.property.SimpleLongProperty; import lombok.Getter; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; @@ -107,9 +101,6 @@ public class WalletsSetup { private final NetworkParameters params; private final File walletDir; private final int socks5DiscoverMode; - private final IntegerProperty numPeers = new SimpleIntegerProperty(0); - private final LongProperty chainHeight = new SimpleLongProperty(0); - private final DownloadListener downloadListener = new DownloadListener(); private final List setupTaskHandlers = new ArrayList<>(); private final List setupCompletedHandlers = new ArrayList<>(); public final BooleanProperty shutDownComplete = new SimpleBooleanProperty(); @@ -172,12 +163,12 @@ public class WalletsSetup { backupWallets(); final Socks5Proxy socks5Proxy = socks5ProxyProvider.getSocks5Proxy(); - log.info("Socks5Proxy for bitcoinj: socks5Proxy=" + socks5Proxy); + log.info("Using Socks5Proxy: " + socks5Proxy); walletConfig = new WalletConfig(params, walletDir, "haveno") { + @Override protected void onSetupCompleted() { - //We are here in the btcj thread Thread[ STARTING,5,main] super.onSetupCompleted(); // run external startup handlers @@ -244,8 +235,6 @@ public class WalletsSetup { } } - walletConfig.setDownloadListener(downloadListener); - // If seed is non-null it means we are restoring from backup. if (seed != null) { walletConfig.restoreWalletFromSeed(seed); @@ -430,26 +419,6 @@ public class WalletsSetup { return walletConfig; } - public ReadOnlyIntegerProperty numPeersProperty() { - return numPeers; - } - - public LongProperty chainHeightProperty() { - return chainHeight; - } - - public ReadOnlyDoubleProperty downloadPercentageProperty() { - return downloadListener.percentageProperty(); - } - - public boolean isDownloadComplete() { - return downloadPercentageProperty().get() == 1d; - } - - public boolean isChainHeightSyncedWithinTolerance() { - throw new RuntimeException("WalletsSetup.isChainHeightSyncedWithinTolerance() not implemented for BTC"); - } - public Set
getAddressesByContext(@SuppressWarnings("SameParameterValue") AddressEntry.Context context) { return addressEntryList.getAddressEntriesAsListImmutable().stream() .filter(addressEntry -> addressEntry.getContext() == context) @@ -463,10 +432,6 @@ public class WalletsSetup { .collect(Collectors.toSet()); } - public boolean hasSufficientPeersForBroadcast() { - return numPeers.get() >= getMinBroadcastConnections(); - } - public int getMinBroadcastConnections() { return walletConfig.getMinBroadcastConnections(); } diff --git a/core/src/main/java/haveno/core/xmr/wallet/BtcWalletService.java b/core/src/main/java/haveno/core/xmr/wallet/BtcWalletService.java index 6a088f3b..e0f9cc2d 100644 --- a/core/src/main/java/haveno/core/xmr/wallet/BtcWalletService.java +++ b/core/src/main/java/haveno/core/xmr/wallet/BtcWalletService.java @@ -92,6 +92,10 @@ public class BtcWalletService extends WalletService { // Overridden Methods /////////////////////////////////////////////////////////////////////////////////////////// + public boolean isWalletSyncedWithinTolerance() { + throw new RuntimeException("Not implemented"); + } + @Override void decryptWallet(@NotNull KeyParameter key) { super.decryptWallet(key); diff --git a/core/src/main/java/haveno/core/xmr/wallet/WalletService.java b/core/src/main/java/haveno/core/xmr/wallet/WalletService.java index ed4bc13f..fb42904c 100644 --- a/core/src/main/java/haveno/core/xmr/wallet/WalletService.java +++ b/core/src/main/java/haveno/core/xmr/wallet/WalletService.java @@ -538,9 +538,7 @@ public abstract class WalletService { return isWalletReady() && chain != null ? chain.getBestChainHeight() : 0; } - public boolean isChainHeightSyncedWithinTolerance() { - return walletsSetup.isChainHeightSyncedWithinTolerance(); - } + public abstract boolean isWalletSyncedWithinTolerance(); public Transaction getClonedTransaction(Transaction tx) { return new Transaction(params, tx.bitcoinSerialize()); diff --git a/core/src/main/java/haveno/core/xmr/wallet/WalletsManager.java b/core/src/main/java/haveno/core/xmr/wallet/WalletsManager.java index 4ecdc195..3cdfc4ca 100644 --- a/core/src/main/java/haveno/core/xmr/wallet/WalletsManager.java +++ b/core/src/main/java/haveno/core/xmr/wallet/WalletsManager.java @@ -97,7 +97,7 @@ public class WalletsManager { } public boolean areWalletsAvailable() { - return xmrWalletService.isWalletReady(); + return xmrWalletService.isWalletAvailable(); } public KeyCrypterScrypt getKeyCrypterScrypt() { 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 b7c04973..9e35d575 100644 --- a/core/src/main/java/haveno/core/xmr/wallet/XmrWalletService.java +++ b/core/src/main/java/haveno/core/xmr/wallet/XmrWalletService.java @@ -21,6 +21,7 @@ import haveno.core.user.Preferences; import haveno.core.xmr.listeners.XmrBalanceListener; import haveno.core.xmr.model.XmrAddressEntry; import haveno.core.xmr.model.XmrAddressEntryList; +import haveno.core.xmr.setup.DownloadListener; import haveno.core.xmr.setup.MoneroWalletRpcManager; import haveno.core.xmr.setup.WalletsSetup; import monero.common.MoneroError; @@ -69,11 +70,15 @@ import java.util.Set; import java.util.TreeSet; import java.util.concurrent.Callable; import java.util.concurrent.CopyOnWriteArraySet; +import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.stream.Collectors; import java.util.stream.Stream; +import javafx.beans.property.LongProperty; +import javafx.beans.property.ReadOnlyDoubleProperty; +import javafx.beans.property.SimpleLongProperty; import static com.google.common.base.Preconditions.checkState; @@ -104,6 +109,8 @@ public class XmrWalletService { private final CoreMoneroConnectionsService connectionsService; private final XmrAddressEntryList xmrAddressEntryList; private final WalletsSetup walletsSetup; + private final DownloadListener downloadListener = new DownloadListener(); + private final LongProperty walletHeight = new SimpleLongProperty(0); private final File walletDir; private final File xmrWalletFile; @@ -196,7 +203,7 @@ public class XmrWalletService { saveWallet(getWallet(), backup); } - public boolean isWalletReady() { + public boolean isWalletAvailable() { try { return getWallet() != null; } catch (Exception e) { @@ -208,6 +215,22 @@ public class XmrWalletService { return accountService.getPassword() != null; } + public boolean isWalletSynced() { + return downloadPercentageProperty().get() == 1d; + } + + public ReadOnlyDoubleProperty downloadPercentageProperty() { + return downloadListener.percentageProperty(); + } + + private void doneDownload() { + downloadListener.doneDownload(); + } + + public LongProperty walletHeightProperty() { + return walletHeight; + } + public MoneroDaemonRpc getDaemon() { return connectionsService.getDaemon(); } @@ -651,12 +674,19 @@ public class XmrWalletService { private void initialize() { - // set and listen to daemon connection - connectionsService.addConnectionListener(newConnection -> { - onConnectionChanged(newConnection); - }); + // listen for connection changes + connectionsService.addConnectionListener(newConnection -> onConnectionChanged(newConnection)); - // initialize main wallet if connected or previously created + // wait for monerod to sync + if (connectionsService.downloadPercentageProperty().get() != 1) { + CountDownLatch latch = new CountDownLatch(1); + connectionsService.downloadPercentageProperty().addListener((obs, oldVal, newVal) -> { + if (connectionsService.downloadPercentageProperty().get() == 1) latch.countDown(); + }); + HavenoUtils.awaitLatch(latch); + } + + // initialize main wallet maybeInitMainWallet(true); } @@ -700,8 +730,8 @@ public class XmrWalletService { // reapply connection after wallet synced onConnectionChanged(connectionsService.getConnection()); - // TODO: using this to signify both daemon and wallet synced, use separate sync handlers? - connectionsService.doneDownload(); + // signal that main wallet is synced + doneDownload(); // notify setup that main wallet is initialized // TODO: app fully initializes after this is set to true, even though wallet might not be initialized if unconnected. wallet will be created when connection detected @@ -1242,6 +1272,7 @@ public class XmrWalletService { UserThread.execute(new Runnable() { @Override public void run() { + walletHeight.set(height); for (MoneroWalletListenerI listener : walletListeners) listener.onNewBlock(height); } }); diff --git a/desktop/src/main/java/haveno/desktop/main/offer/offerbook/OfferBookViewModel.java b/desktop/src/main/java/haveno/desktop/main/offer/offerbook/OfferBookViewModel.java index 50c9400a..44d6d21f 100644 --- a/desktop/src/main/java/haveno/desktop/main/offer/offerbook/OfferBookViewModel.java +++ b/desktop/src/main/java/haveno/desktop/main/offer/offerbook/OfferBookViewModel.java @@ -553,6 +553,7 @@ abstract class OfferBookViewModel extends ActivatableViewModel { boolean canCreateOrTakeOffer() { return GUIUtil.canCreateOrTakeOfferOrShowPopup(user, navigation) && + GUIUtil.isChainHeightSyncedWithinToleranceOrShowPopup(openOfferManager.getConnectionsService()) && GUIUtil.isBootstrappedOrShowPopup(p2PService); }