From fd69f4250bfc93582a5c8783d72197151f7b8b57 Mon Sep 17 00:00:00 2001 From: woodser Date: Sun, 2 Apr 2023 17:11:01 -0400 Subject: [PATCH] support tor connection to monero network through monero-java cleanup startup routine for stability remove call to `get_connections` increase wallet startup timeout to 1 hour increase app startup timeout to 5 minutes skip checkstyle in make commands --- Makefile | 26 ++++- .../api/CoreMoneroConnectionsService.java | 98 ++++++++++++------- .../java/haveno/core/app/HavenoSetup.java | 12 +-- .../java/haveno/core/app/P2PNetworkSetup.java | 6 +- .../java/haveno/core/trade/HavenoUtils.java | 2 +- .../main/java/haveno/core/trade/Trade.java | 14 ++- .../java/haveno/core/trade/TradeManager.java | 2 +- .../haveno/core/xmr/setup/WalletsSetup.java | 4 +- .../core/xmr/wallet/XmrWalletService.java | 71 ++++++++------ .../java/haveno/desktop/app/HavenoApp.java | 2 +- 10 files changed, 149 insertions(+), 88 deletions(-) diff --git a/Makefile b/Makefile index d3ec4e5657..014355c8d4 100644 --- a/Makefile +++ b/Makefile @@ -16,11 +16,14 @@ haveno: # build haveno without tests skip-tests: localnet - ./gradlew build -x test + ./gradlew build -x test -x checkstyleMain -x checkstyleTest # quick build desktop and daemon apps without tests haveno-apps: - ./gradlew :core:compileJava :desktop:build -x test + ./gradlew :core:compileJava :desktop:build -x test -x checkstyleMain -x checkstyleTest + +refresh-deps: + ./gradlew --write-verification-metadata sha256 && ./gradlew build --refresh-keys --refresh-dependencies -x test -x checkstyleMain -x checkstyleTest deploy: # create a new screen session named 'localnet' @@ -84,6 +87,17 @@ monerod-local2: --rpc-access-control-origins http://localhost:8080 \ --fixed-difficulty 300 +funding-wallet-stagenet: + ./.localnet/monero-wallet-rpc \ + --rpc-bind-port 18084 \ + --rpc-login rpc_user:abc123 \ + --rpc-access-control-origins http://localhost:8080 \ + --wallet-dir ./.localnet \ + --daemon-ssl-allow-any-cert \ + --daemon-address http://127.0.0.1:38081 + +#--proxy 127.0.0.1:49775 \ + funding-wallet-local: ./.localnet/monero-wallet-rpc \ --testnet \ @@ -214,10 +228,11 @@ arbitrator-daemon-stagenet: --appName=haveno-XMR_STAGENET_arbitrator \ --apiPassword=apitest \ --apiPort=9998 \ - --passwordRequired=false + --passwordRequired=false \ + --xmrNode=http://127.0.0.1:38081 +# Arbitrator needs to be registered before making trades arbitrator-desktop-stagenet: - # Arbitrator needs to be registered before making trades ./haveno-desktop$(APP_EXT) \ --baseCurrencyNetwork=XMR_STAGENET \ --useLocalhostForP2P=false \ @@ -225,7 +240,8 @@ arbitrator-desktop-stagenet: --nodePort=4444 \ --appName=haveno-XMR_STAGENET_arbitrator \ --apiPassword=apitest \ - --apiPort=9998 + --apiPort=9998 \ + --xmrNode=http://127.0.0.1:38081 user1-daemon-stagenet: ./haveno-daemon$(APP_EXT) \ diff --git a/core/src/main/java/haveno/core/api/CoreMoneroConnectionsService.java b/core/src/main/java/haveno/core/api/CoreMoneroConnectionsService.java index 69a2b1a2c5..c1f05f3e83 100644 --- a/core/src/main/java/haveno/core/api/CoreMoneroConnectionsService.java +++ b/core/src/main/java/haveno/core/api/CoreMoneroConnectionsService.java @@ -1,5 +1,6 @@ package haveno.core.api; +import haveno.common.UserThread; import haveno.common.app.DevEnv; import haveno.common.config.BaseCurrencyNetwork; import haveno.common.config.Config; @@ -7,6 +8,7 @@ import haveno.core.trade.HavenoUtils; import haveno.core.xmr.model.EncryptedConnectionList; import haveno.core.xmr.setup.DownloadListener; import haveno.core.xmr.setup.WalletsSetup; +import haveno.network.Socks5ProxyProvider; import javafx.beans.property.IntegerProperty; import javafx.beans.property.LongProperty; import javafx.beans.property.ObjectProperty; @@ -20,7 +22,6 @@ import lombok.Getter; import lombok.extern.slf4j.Slf4j; import monero.common.MoneroConnectionManager; import monero.common.MoneroConnectionManagerListener; -import monero.common.MoneroError; import monero.common.MoneroRpcConnection; import monero.common.TaskLooper; import monero.daemon.MoneroDaemonRpc; @@ -34,6 +35,7 @@ import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.stream.Collectors; @Slf4j @@ -60,7 +62,7 @@ public final class CoreMoneroConnectionsService { new MoneroRpcConnection("http://stagenet.melo.tools:38081").setPriority(2), new MoneroRpcConnection("http://node.sethforprivacy.com:38089").setPriority(2), new MoneroRpcConnection("http://node2.sethforprivacy.com:38089").setPriority(2), - new MoneroRpcConnection("http://ct36dsbe3oubpbebpxmiqz4uqk6zb6nhmkhoekileo4fts23rvuse2qd.onion:38081").setPriority(2) + new MoneroRpcConnection("http://plowsof3t5hogddwabaeiyrno25efmzfxyro2vligremt7sxpsclfaid.onion:38089").setPriority(2) )); DEFAULT_CONNECTIONS.put(BaseCurrencyNetwork.XMR_MAINNET, Arrays.asList( new MoneroRpcConnection("http://127.0.0.1:18081").setPriority(1), @@ -84,6 +86,7 @@ public final class CoreMoneroConnectionsService { private final IntegerProperty numPeers = new SimpleIntegerProperty(0); private final LongProperty chainHeight = new SimpleLongProperty(0); private final DownloadListener downloadListener = new DownloadListener(); + private Socks5ProxyProvider socks5ProxyProvider; private MoneroDaemonRpc daemon; @Getter @@ -98,16 +101,15 @@ public final class CoreMoneroConnectionsService { CoreAccountService accountService, CoreMoneroNodeService nodeService, MoneroConnectionManager connectionManager, - EncryptedConnectionList connectionList) { + EncryptedConnectionList connectionList, + Socks5ProxyProvider socks5ProxyProvider) { this.config = config; this.coreContext = coreContext; this.accountService = accountService; this.nodeService = nodeService; this.connectionManager = connectionManager; this.connectionList = connectionList; - - // initialize immediately if monerod configured - if (!"".equals(config.xmrNode)) initialize(); + this.socks5ProxyProvider = socks5ProxyProvider; // initialize after account open and basic setup walletsSetup.addSetupTaskHandler(() -> { // TODO: use something better than legacy WalletSetup for notification to initialize @@ -145,6 +147,10 @@ public final class CoreMoneroConnectionsService { return this.daemon; } + public String getProxyUri() { + return socks5ProxyProvider.getSocks5Proxy() == null ? null : socks5ProxyProvider.getSocks5Proxy().getInetAddress().getHostAddress() + ":" + socks5ProxyProvider.getSocks5Proxy().getPort(); + } + public void addListener(MoneroConnectionManagerListener listener) { synchronized (lock) { connectionManager.addListener(listener); @@ -319,30 +325,41 @@ public final class CoreMoneroConnectionsService { private void initialize() { synchronized (lock) { - // reset connection manager's connections and listeners + // reset connection manager connectionManager.reset(); + connectionManager.setTimeout(REFRESH_PERIOD_REMOTE_MS); // load connections - connectionList.getConnections().forEach(connectionManager::addConnection); + log.info("TOR proxy URI: " + getProxyUri()); + for (MoneroRpcConnection connection : connectionList.getConnections()) { + if (connection.isOnion()) connection.setProxyUri(getProxyUri()); + connectionManager.addConnection(connection); + } log.info("Read " + connectionList.getConnections().size() + " connections from disk"); // add default connections for (MoneroRpcConnection connection : DEFAULT_CONNECTIONS.get(Config.baseCurrencyNetwork())) { if (connectionList.hasConnection(connection.getUri())) continue; + if (connection.isOnion()) connection.setProxyUri(getProxyUri()); addConnection(connection); } - // restore last used connection if present - var currentConnectionUri = connectionList.getCurrentConnectionUri(); - if (currentConnectionUri.isPresent()) connectionManager.setConnection(currentConnectionUri.get()); + // restore last used connection if unconfigured and present + Optional currentConnectionUri = null; + if ("".equals(config.xmrNode)) { + currentConnectionUri = connectionList.getCurrentConnectionUri(); + if (currentConnectionUri.isPresent()) connectionManager.setConnection(currentConnectionUri.get()); + } else if (!isInitialized) { - // set monero connection from startup arguments - if (!isInitialized && !"".equals(config.xmrNode)) { - connectionManager.setConnection(new MoneroRpcConnection(config.xmrNode, config.xmrNodeUsername, config.xmrNodePassword).setPriority(1)); + // set monero connection from startup arguments + MoneroRpcConnection connection = new MoneroRpcConnection(config.xmrNode, config.xmrNodeUsername, config.xmrNodePassword).setPriority(1); + if (connection.isOnion()) connection.setProxyUri(getProxyUri()); + connectionManager.setConnection(connection); + currentConnectionUri = Optional.of(connection.getUri()); } - // restore configuration - connectionManager.setAutoSwitch(connectionList.getAutoSwitch()); + // restore configuration and check connection + if ("".equals(config.xmrNode)) connectionManager.setAutoSwitch(connectionList.getAutoSwitch()); long refreshPeriod = connectionList.getRefreshPeriod(); if (refreshPeriod > 0) connectionManager.startCheckingConnection(refreshPeriod); else if (refreshPeriod == 0) connectionManager.startCheckingConnection(); @@ -351,9 +368,6 @@ public final class CoreMoneroConnectionsService { // run once if (!isInitialized) { - // register connection change listener - connectionManager.addListener(this::onConnectionChanged); - // register local node listener nodeService.addListener(new MoneroNodeServiceListener() { @Override @@ -369,8 +383,6 @@ public final class CoreMoneroConnectionsService { checkConnection(); } }); - - isInitialized = true; } // if offline and last connection is local, start local node if offline @@ -385,7 +397,7 @@ public final class CoreMoneroConnectionsService { }); // prefer to connect to local node unless prevented by configuration - if (("".equals(config.xmrNode) || HavenoUtils.isLocalHost(config.xmrNode)) && + if ("".equals(config.xmrNode) && (!connectionManager.isConnected() || connectionManager.getAutoSwitch()) && nodeService.isConnected()) { MoneroRpcConnection connection = connectionManager.getConnectionByUri(nodeService.getDaemon().getRpcConnection().getUri()); @@ -401,12 +413,19 @@ public final class CoreMoneroConnectionsService { connectionManager.setConnection(connectionManager.getBestAvailableConnection()); } - // update connection + // register connection change listener + if (!isInitialized) { + connectionManager.addListener(this::onConnectionChanged); + isInitialized = true; + } + + // announce connection onConnectionChanged(connectionManager.getConnection()); } } private void onConnectionChanged(MoneroRpcConnection currentConnection) { + // TODO: ignore if shutdown synchronized (lock) { if (currentConnection == null) { daemon = null; @@ -422,12 +441,17 @@ public final class CoreMoneroConnectionsService { } private void startPollingDaemon() { - if (updateDaemonLooper != null) updateDaemonLooper.stop(); - updateDaemonInfo(); - updateDaemonLooper = new TaskLooper(() -> { + synchronized (lock) { updateDaemonInfo(); - }); - updateDaemonLooper.start(getDefaultRefreshPeriodMs()); + if (updateDaemonLooper != null) updateDaemonLooper.stop(); + UserThread.runAfter(() -> { + synchronized (lock) { + if (updateDaemonLooper != null) updateDaemonLooper.stop(); + updateDaemonLooper = new TaskLooper(() -> updateDaemonInfo()); + updateDaemonLooper.start(getDefaultRefreshPeriodMs()); + } + }, getDefaultRefreshPeriodMs() / 1000); + } } private void updateDaemonInfo() { @@ -438,12 +462,18 @@ public final class CoreMoneroConnectionsService { //System.out.println(JsonUtils.serialize(lastInfo)); //System.out.println(JsonUtils.serialize(daemon.getSyncInfo())); chainHeight.set(lastInfo.getTargetHeight() == 0 ? lastInfo.getHeight() : lastInfo.getTargetHeight()); - try { - peers.set(getOnlinePeers()); - } catch (MoneroError err) { - peers.set(new ArrayList()); // TODO: peers unknown due to restricted RPC call - } - numPeers.set(peers.get().size()); + + // set peer connections + // TODO: peers often uknown due to restricted RPC call, skipping call to get peer connections + // try { + // peers.set(getOnlinePeers()); + // } catch (Exception err) { + // // TODO: peers unknown due to restricted RPC call + // } + // numPeers.set(peers.get().size()); + numPeers.set(lastInfo.getNumOutgoingConnections() + lastInfo.getNumIncomingConnections()); + peers.set(new ArrayList()); + if (lastErrorTimestamp != null) { log.info("Successfully fetched daemon info after previous error"); lastErrorTimestamp = null; diff --git a/core/src/main/java/haveno/core/app/HavenoSetup.java b/core/src/main/java/haveno/core/app/HavenoSetup.java index d8869ac8c9..ae9e30c5f3 100644 --- a/core/src/main/java/haveno/core/app/HavenoSetup.java +++ b/core/src/main/java/haveno/core/app/HavenoSetup.java @@ -17,11 +17,9 @@ package haveno.core.app; -import ch.qos.logback.classic.Level; import haveno.common.Timer; import haveno.common.UserThread; import haveno.common.app.DevEnv; -import haveno.common.app.Log; import haveno.common.app.Version; import haveno.common.config.BaseCurrencyNetwork; import haveno.common.config.Config; @@ -102,7 +100,7 @@ public class HavenoSetup { private static final String VERSION_FILE_NAME = "version"; private static final String RESYNC_SPV_FILE_NAME = "resyncSpv"; - private static final long STARTUP_TIMEOUT_MINUTES = 4; + private static final long STARTUP_TIMEOUT_MINUTES = 5; private final DomainInitialisation domainInitialisation; private final P2PNetworkSetup p2PNetworkSetup; @@ -403,9 +401,9 @@ public class HavenoSetup { if (displayTorNetworkSettingsHandler != null) displayTorNetworkSettingsHandler.accept(true); - log.info("Set log level for org.berndpruenster.netlayer classes to DEBUG to show more details for " + - "Tor network connection issues"); - Log.setCustomLogLevel("org.berndpruenster.netlayer", Level.DEBUG); + // log.info("Set log level for org.berndpruenster.netlayer classes to DEBUG to show more details for " + + // "Tor network connection issues"); + // Log.setCustomLogLevel("org.berndpruenster.netlayer", Level.DEBUG); }, STARTUP_TIMEOUT_MINUTES, TimeUnit.MINUTES); @@ -444,7 +442,7 @@ public class HavenoSetup { checkForInvalidMakerFeeTxs(); } }, - () -> walletInitialized.set(true)); + () -> {}); } private void initDomainServices() { diff --git a/core/src/main/java/haveno/core/app/P2PNetworkSetup.java b/core/src/main/java/haveno/core/app/P2PNetworkSetup.java index c8655c3108..3158785848 100644 --- a/core/src/main/java/haveno/core/app/P2PNetworkSetup.java +++ b/core/src/main/java/haveno/core/app/P2PNetworkSetup.java @@ -142,12 +142,12 @@ public class P2PNetworkSetup { bootstrapState.set(Res.get("mainView.bootstrapState.torNodeCreated")); p2PNetworkIconId.set("image-connection-tor"); - // invoke handler to initialize wallet - initWalletServiceHandler.run(); - // We want to get early connected to the price relay so we call it already now priceFeedService.setCurrencyCodeOnInit(); priceFeedService.requestPrices(); + + // invoke handler to initialize wallet + initWalletServiceHandler.run(); } @Override diff --git a/core/src/main/java/haveno/core/trade/HavenoUtils.java b/core/src/main/java/haveno/core/trade/HavenoUtils.java index ee50a6ebec..5e3c51219d 100644 --- a/core/src/main/java/haveno/core/trade/HavenoUtils.java +++ b/core/src/main/java/haveno/core/trade/HavenoUtils.java @@ -424,7 +424,7 @@ public class HavenoUtils { public static boolean isLocalHost(String uri) { try { String host = new URI(uri).getHost(); - return host.equals(LOOPBACK_HOST) || host.equals(LOCALHOST); + return LOOPBACK_HOST.equals(host) || LOCALHOST.equals(host); } catch (Exception e) { throw new RuntimeException(e); } diff --git a/core/src/main/java/haveno/core/trade/Trade.java b/core/src/main/java/haveno/core/trade/Trade.java index d0192aad20..87ea88e4cc 100644 --- a/core/src/main/java/haveno/core/trade/Trade.java +++ b/core/src/main/java/haveno/core/trade/Trade.java @@ -1662,12 +1662,16 @@ public abstract class Trade implements Tradable, Model { private void setWalletRefreshPeriod(long walletRefreshPeriod) { if (this.isShutDown) return; if (this.walletRefreshPeriod != null && this.walletRefreshPeriod == walletRefreshPeriod) return; - log.info("Setting wallet refresh rate for {} {} to {}", getClass().getSimpleName(), getId(), walletRefreshPeriod); this.walletRefreshPeriod = walletRefreshPeriod; - getWallet().startSyncing(getWalletRefreshPeriod()); // TODO (monero-project): wallet rpc waits until last sync period finishes before starting new sync period - if (txPollLooper != null) { - txPollLooper.stop(); - txPollLooper = null; + synchronized (walletLock) { + if (getWallet() != null) { + log.info("Setting wallet refresh rate for {} {} to {}", getClass().getSimpleName(), getId(), walletRefreshPeriod); + getWallet().startSyncing(getWalletRefreshPeriod()); // TODO (monero-project): wallet rpc waits until last sync period finishes before starting new sync period + } + if (txPollLooper != null) { + txPollLooper.stop(); + txPollLooper = null; + } } startPolling(); } diff --git a/core/src/main/java/haveno/core/trade/TradeManager.java b/core/src/main/java/haveno/core/trade/TradeManager.java index 607a57631b..1450bcb0f5 100644 --- a/core/src/main/java/haveno/core/trade/TradeManager.java +++ b/core/src/main/java/haveno/core/trade/TradeManager.java @@ -349,7 +349,7 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi .collect(Collectors.toSet()); unreservedFrozenKeyImages.removeAll(reservedKeyImages); if (!unreservedFrozenKeyImages.isEmpty()) { - log.info("Thawing outputs which are not reserved for offer or trade: " + unreservedFrozenKeyImages); + log.warn("Thawing outputs which are not reserved for offer or trade: " + unreservedFrozenKeyImages); xmrWalletService.thawOutputs(unreservedFrozenKeyImages); xmrWalletService.saveMainWallet(); } 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 40c26c9cac..17e51573a5 100644 --- a/core/src/main/java/haveno/core/xmr/setup/WalletsSetup.java +++ b/core/src/main/java/haveno/core/xmr/setup/WalletsSetup.java @@ -92,7 +92,7 @@ public class WalletsSetup { @Getter public final BooleanProperty walletsSetupFailed = new SimpleBooleanProperty(); - private static final long STARTUP_TIMEOUT = 180; + private static final long STARTUP_TIMEOUT_SECONDS = 3600; // 1 hour private static final String SPV_CHAIN_FILE_NAME = "haveno.spvchain"; private final RegTestHost regTestHost; @@ -167,7 +167,7 @@ public class WalletsSetup { Timer timeoutTimer = UserThread.runAfter(() -> exceptionHandler.handleException(new TimeoutException("Wallet did not initialize in " + - STARTUP_TIMEOUT + " seconds.")), STARTUP_TIMEOUT); + STARTUP_TIMEOUT_SECONDS + " seconds.")), STARTUP_TIMEOUT_SECONDS); backupWallets(); 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 7ea2d8a97a..6468e12042 100644 --- a/core/src/main/java/haveno/core/xmr/wallet/XmrWalletService.java +++ b/core/src/main/java/haveno/core/xmr/wallet/XmrWalletService.java @@ -211,7 +211,7 @@ public class XmrWalletService { public MoneroWalletRpc createWallet(String walletName) { log.info("{}.createWallet({})", getClass().getSimpleName(), walletName); if (isShutDown) throw new IllegalStateException("Cannot create wallet because shutting down"); - return createWallet(new MoneroWalletConfig() + return createWalletRpc(new MoneroWalletConfig() .setPath(walletName) .setPassword(getWalletPassword()), null); @@ -220,7 +220,7 @@ public class XmrWalletService { public MoneroWalletRpc openWallet(String walletName) { log.info("{}.openWallet({})", getClass().getSimpleName(), walletName); if (isShutDown) throw new IllegalStateException("Cannot open wallet because shutting down"); - return openWallet(new MoneroWalletConfig() + return openWalletRpc(new MoneroWalletConfig() .setPath(walletName) .setPassword(getWalletPassword()), null); @@ -546,51 +546,49 @@ public class XmrWalletService { private void maybeInitMainWallet() { if (wallet != null) throw new RuntimeException("Main wallet is already initialized"); + MoneroDaemonRpc daemon = connectionsService.getDaemon(); + log.info("Initializing main wallet with " + (daemon == null ? "daemon: null" : "monerod uri=" + daemon.getRpcConnection().getUri() + ", height=" + connectionsService.getLastInfo().getHeight())); // open or create wallet MoneroWalletConfig walletConfig = new MoneroWalletConfig().setPath(MONERO_WALLET_NAME).setPassword(getWalletPassword()); if (MoneroUtils.walletExists(xmrWalletFile.getPath())) { - wallet = openWallet(walletConfig, rpcBindPort); + wallet = openWalletRpc(walletConfig, rpcBindPort); } else if (connectionsService.getConnection() != null && Boolean.TRUE.equals(connectionsService.getConnection().isConnected())) { - wallet = createWallet(walletConfig, rpcBindPort); + wallet = createWalletRpc(walletConfig, rpcBindPort); } - // wallet is not initialized until connected to a daemon + // handle when wallet initialized and synced if (wallet != null) { - if (connectionsService.getDaemon() == null) System.out.println("Daemon: null"); - else { - System.out.println("Daemon uri: " + connectionsService.getDaemon().getRpcConnection().getUri()); - System.out.println("Daemon height: " + connectionsService.getDaemon().getInfo().getHeight()); - } - System.out.println("Monero wallet uri: " + wallet.getRpcConnection().getUri()); - System.out.println("Monero wallet path: " + wallet.getPath()); - System.out.println("Monero wallet primary address: " + wallet.getPrimaryAddress()); - - // sync wallet which updates app startup state + log.info("Monero wallet uri={}, path={}", wallet.getRpcConnection().getUri(), wallet.getPath()); try { + + // sync main wallet log.info("Syncing main wallet"); long time = System.currentTimeMillis(); wallet.sync(); // blocking log.info("Done syncing main wallet in " + (System.currentTimeMillis() - time) + " ms"); wallet.startSyncing(connectionsService.getDefaultRefreshPeriodMs()); - connectionsService.doneDownload(); // TODO: using this to signify both daemon and wallet synced, refactor sync handling of both - saveMainWallet(false); // skip backup on open + if (getMoneroNetworkType() != MoneroNetworkType.MAINNET) log.info("Monero wallet balance={}, unlocked balance={}", wallet.getBalance(0), wallet.getUnlockedBalance(0)); + + // TODO: using this to signify both daemon and wallet synced, refactor sync handling of both + connectionsService.doneDownload(); + + // save but skip backup on initialization + saveMainWallet(false); } catch (Exception e) { log.warn("Error syncing main wallet: {}", e.getMessage()); } - - System.out.println("Monero wallet balance: " + wallet.getBalance(0)); - System.out.println("Monero wallet unlocked balance: " + wallet.getUnlockedBalance(0)); - + // notify setup that main wallet is initialized - havenoSetup.getWalletInitialized().set(true); // TODO: change to listener pattern? + // TODO: move to try..catch? refactor startup to call this and sync off main thread? + havenoSetup.getWalletInitialized().set(true); // TODO: change to listener pattern // register internal listener to notify external listeners wallet.addListener(new XmrWalletListener()); } } - private MoneroWalletRpc createWallet(MoneroWalletConfig config, Integer port) { + private MoneroWalletRpc createWalletRpc(MoneroWalletConfig config, Integer port) { // must be connected to daemon MoneroRpcConnection connection = connectionsService.getConnection(); @@ -602,10 +600,15 @@ public class XmrWalletService { // create wallet try { - log.info("Creating wallet " + config.getPath()); + + // prevent wallet rpc from syncing + walletRpc.stopSyncing(); + + // create wallet + log.info("Creating wallet " + config.getPath() + " connected to daemon " + connection.getUri()); long time = System.currentTimeMillis(); walletRpc.createWallet(config); - log.info("Done creating wallet " + walletRpc.getPath() + " in " + (System.currentTimeMillis() - time) + " ms"); + log.info("Done creating wallet " + config.getPath() + " in " + (System.currentTimeMillis() - time) + " ms"); return walletRpc; } catch (Exception e) { e.printStackTrace(); @@ -614,17 +617,21 @@ public class XmrWalletService { } } - private MoneroWalletRpc openWallet(MoneroWalletConfig config, Integer port) { + private MoneroWalletRpc openWalletRpc(MoneroWalletConfig config, Integer port) { // start monero-wallet-rpc instance MoneroWalletRpc walletRpc = startWalletRpcInstance(port); // open wallet try { + + // prevent wallet rpc from syncing + walletRpc.stopSyncing(); + + // open wallet log.info("Opening wallet " + config.getPath()); - walletRpc.openWallet(config); - walletRpc.setDaemonConnection(connectionsService.getConnection()); - log.info("Done opening wallet " + walletRpc.getPath()); + walletRpc.openWallet(config.setServer(connectionsService.getConnection())); + log.info("Done opening wallet " + config.getPath()); return walletRpc; } catch (Exception e) { e.printStackTrace(); @@ -655,6 +662,10 @@ public class XmrWalletService { if (connection != null) { cmd.add("--daemon-address"); cmd.add(connection.getUri()); + if (connection.isOnion() && connection.getProxyUri() != null) { + cmd.add("--proxy"); + cmd.add(connection.getProxyUri()); + } if (connection.getUsername() != null) { cmd.add("--daemon-login"); cmd.add(connection.getUsername() + ":" + connection.getPassword()); @@ -669,7 +680,9 @@ public class XmrWalletService { return MONERO_WALLET_RPC_MANAGER.startInstance(cmd); } + // TODO: monero-wallet-rpc needs restarted if applying tor proxy private void setDaemonConnection(MoneroRpcConnection connection) { + if (isShutDown) return; log.info("Setting wallet daemon connection: " + (connection == null ? null : connection.getUri())); if (wallet == null) maybeInitMainWallet(); else { diff --git a/desktop/src/main/java/haveno/desktop/app/HavenoApp.java b/desktop/src/main/java/haveno/desktop/app/HavenoApp.java index d094177aed..71ad08692a 100644 --- a/desktop/src/main/java/haveno/desktop/app/HavenoApp.java +++ b/desktop/src/main/java/haveno/desktop/app/HavenoApp.java @@ -117,7 +117,7 @@ public class HavenoApp extends Application implements UncaughtExceptionHandler { } public void startApplication(Runnable onApplicationStartedHandler) { - log.info("Running startApplication..."); + log.info("Starting application"); try { mainView = loadMainView(injector); mainView.setOnApplicationStartedHandler(onApplicationStartedHandler);