From 7d21bdf9f38fc274c82c1943c1287d9d0527e4a6 Mon Sep 17 00:00:00 2001 From: premek <1145361+premek@users.noreply.github.com> Date: Mon, 15 Nov 2021 18:02:58 +0100 Subject: [PATCH] add config option to specify wallet rpc bind port --- Makefile | 12 ++++-- .../main/java/bisq/common/config/Config.java | 9 +++++ .../java/bisq/core/btc/BitcoinModule.java | 2 + .../btc/setup/MoneroWalletRpcManager.java | 23 ++++++----- .../bisq/core/btc/setup/WalletConfig.java | 39 ++++++++++++------- .../bisq/core/btc/setup/WalletsSetup.java | 10 ++--- .../core/btc/wallet/XmrWalletService.java | 6 ++- 7 files changed, 65 insertions(+), 36 deletions(-) diff --git a/Makefile b/Makefile index c71520738e..daa5247fdb 100644 --- a/Makefile +++ b/Makefile @@ -62,7 +62,8 @@ alice-desktop: --nodePort=5555 \ --appName=haveno-XMR_STAGENET_Alice \ --apiPassword=apitest \ - --apiPort=9999 + --apiPort=9999 \ + --walletRpcBindPort=38091 alice-daemon: ./haveno-daemon \ @@ -72,7 +73,8 @@ alice-daemon: --nodePort=5555 \ --appName=haveno-XMR_STAGENET_Alice \ --apiPassword=apitest \ - --apiPort=9999 + --apiPort=9999 \ + --walletRpcBindPort=38091 bob-desktop: ./haveno-desktop \ @@ -82,7 +84,8 @@ bob-desktop: --nodePort=6666 \ --appName=haveno-XMR_STAGENET_Bob \ --apiPassword=apitest \ - --apiPort=10000 + --apiPort=10000 \ + --walletRpcBindPort=38092 bob-daemon: ./haveno-daemon \ @@ -92,7 +95,8 @@ bob-daemon: --nodePort=6666 \ --appName=haveno-XMR_STAGENET_Bob \ --apiPassword=apitest \ - --apiPort=10000 + --apiPort=10000 \ + --walletRpcBindPort=38092 monero-shared: ./.localnet/monerod \ diff --git a/common/src/main/java/bisq/common/config/Config.java b/common/src/main/java/bisq/common/config/Config.java index 4b13fbd86c..02b9b2b6da 100644 --- a/common/src/main/java/bisq/common/config/Config.java +++ b/common/src/main/java/bisq/common/config/Config.java @@ -73,6 +73,7 @@ public class Config { public static final String STORAGE_DIR = "storageDir"; public static final String KEY_STORAGE_DIR = "keyStorageDir"; public static final String WALLET_DIR = "walletDir"; + public static final String WALLET_RPC_BIND_PORT = "walletRpcBindPort"; public static final String USE_DEV_PRIVILEGE_KEYS = "useDevPrivilegeKeys"; public static final String DUMP_STATISTICS = "dumpStatistics"; public static final String IGNORE_DEV_MSG = "ignoreDevMsg"; @@ -140,6 +141,7 @@ public class Config { public final String appName; public final File userDataDir; public final File appDataDir; + public final int walletRpcBindPort; public final int nodePort; public final int maxMemory; public final String logLevel; @@ -272,6 +274,12 @@ public class Config { .ofType(Integer.class) .defaultsTo(9999); + ArgumentAcceptingOptionSpec walletRpcBindPortOpt = + parser.accepts(WALLET_RPC_BIND_PORT, "Port to bind the wallet RPC on") + .withRequiredArg() + .ofType(int.class) + .defaultsTo(UNSPECIFIED_PORT); + ArgumentAcceptingOptionSpec maxMemoryOpt = parser.accepts(MAX_MEMORY, "Max. permitted memory (used only by headless versions)") .withRequiredArg() @@ -628,6 +636,7 @@ public class Config { this.helpRequested = options.has(helpOpt); this.configFile = configFile; this.nodePort = options.valueOf(nodePortOpt); + this.walletRpcBindPort = options.valueOf(walletRpcBindPortOpt); this.maxMemory = options.valueOf(maxMemoryOpt); this.logLevel = options.valueOf(logLevelOpt); this.bannedBtcNodes = options.valuesOf(bannedBtcNodesOpt); diff --git a/core/src/main/java/bisq/core/btc/BitcoinModule.java b/core/src/main/java/bisq/core/btc/BitcoinModule.java index 459f30b204..afe309fd4c 100644 --- a/core/src/main/java/bisq/core/btc/BitcoinModule.java +++ b/core/src/main/java/bisq/core/btc/BitcoinModule.java @@ -44,6 +44,7 @@ import java.util.List; import static bisq.common.config.Config.PROVIDERS; import static bisq.common.config.Config.WALLET_DIR; +import static bisq.common.config.Config.WALLET_RPC_BIND_PORT; import static com.google.inject.name.Names.named; public class BitcoinModule extends AppModule { @@ -71,6 +72,7 @@ public class BitcoinModule extends AppModule { } bind(File.class).annotatedWith(named(WALLET_DIR)).toInstance(config.walletDir); + bind(int.class).annotatedWith(named(WALLET_RPC_BIND_PORT)).toInstance(config.walletRpcBindPort); bindConstant().annotatedWith(named(Config.BTC_NODES)).to(config.btcNodes); bindConstant().annotatedWith(named(Config.USER_AGENT)).to(config.userAgent); diff --git a/core/src/main/java/bisq/core/btc/setup/MoneroWalletRpcManager.java b/core/src/main/java/bisq/core/btc/setup/MoneroWalletRpcManager.java index 2bb0b55982..8107ebc1d7 100644 --- a/core/src/main/java/bisq/core/btc/setup/MoneroWalletRpcManager.java +++ b/core/src/main/java/bisq/core/btc/setup/MoneroWalletRpcManager.java @@ -9,7 +9,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; - +import lombok.extern.slf4j.Slf4j; import monero.common.MoneroError; import monero.wallet.MoneroWalletRpc; @@ -17,11 +17,13 @@ import monero.wallet.MoneroWalletRpc; /** * Manages monero-wallet-rpc processes bound to ports. */ +@Slf4j public class MoneroWalletRpcManager { - private static int NUM_ALLOWED_ATTEMPTS = 1; // allow this many attempts to bind to an assigned port + private static final String RPC_BIND_PORT_ARGUMENT = "--rpc-bind-port"; + private static int NUM_ALLOWED_ATTEMPTS = 2; // allow this many attempts to bind to an assigned port private Integer startPort; - private Map registeredPorts = new HashMap(); + private final Map registeredPorts = new HashMap<>(); /** * Manage monero-wallet-rpc instances by auto-assigning ports. @@ -48,8 +50,9 @@ public class MoneroWalletRpcManager { try { // register given port - if (cmd.indexOf("--rpc-bind-port") >= 0) { - int port = Integer.valueOf(cmd.indexOf("--rpc-bind-port") + 1); + if (cmd.contains(RPC_BIND_PORT_ARGUMENT)) { + int portArgumentPosition = cmd.indexOf(RPC_BIND_PORT_ARGUMENT) + 1; + int port = Integer.parseInt(cmd.get(portArgumentPosition)); MoneroWalletRpc walletRpc = new MoneroWalletRpc(cmd); // starts monero-wallet-rpc process registeredPorts.put(port, walletRpc); return walletRpc; @@ -59,19 +62,19 @@ public class MoneroWalletRpcManager { else { int numAttempts = 0; while (numAttempts < NUM_ALLOWED_ATTEMPTS) { + int port = -1; try { numAttempts++; - int port = registerPort(); - List cmdCopy = new ArrayList(cmd); // preserve original cmd - cmdCopy.add("--rpc-bind-port"); + port = registerPort(); + List cmdCopy = new ArrayList<>(cmd); // preserve original cmd + cmdCopy.add(RPC_BIND_PORT_ARGUMENT); cmdCopy.add("" + port); - System.out.println(cmdCopy); MoneroWalletRpc walletRpc = new MoneroWalletRpc(cmdCopy); // start monero-wallet-rpc process registeredPorts.put(port, walletRpc); return walletRpc; } catch (Exception e) { if (numAttempts >= NUM_ALLOWED_ATTEMPTS) { - System.err.println("Unable to start monero-wallet-rpc instance after " + NUM_ALLOWED_ATTEMPTS + " attempts"); + log.error("Unable to start monero-wallet-rpc instance after {} attempts", NUM_ALLOWED_ATTEMPTS); throw e; } } diff --git a/core/src/main/java/bisq/core/btc/setup/WalletConfig.java b/core/src/main/java/bisq/core/btc/setup/WalletConfig.java index efe2df21ec..dd7574b1ac 100644 --- a/core/src/main/java/bisq/core/btc/setup/WalletConfig.java +++ b/core/src/main/java/bisq/core/btc/setup/WalletConfig.java @@ -71,7 +71,9 @@ import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; +import java.util.ArrayList; import java.util.Arrays; +import java.util.List; import java.util.concurrent.TimeUnit; import org.slf4j.Logger; @@ -144,6 +146,7 @@ public class WalletConfig extends AbstractIdleService { protected volatile Wallet vBtcWallet; protected volatile PeerGroup vPeerGroup; + protected final int rpcBindPort; protected final File directory; protected volatile File vXmrWalletFile; protected volatile File vBtcWalletFile; @@ -172,17 +175,21 @@ public class WalletConfig extends AbstractIdleService { /** * Creates a new WalletConfig, with a newly created {@link Context}. Files will be stored in the given directory. */ - public WalletConfig(NetworkParameters params, File directory, String filePrefix) { - this(new Context(params), directory, filePrefix); + public WalletConfig(NetworkParameters params, + File directory, + int rpcBindPort, + String filePrefix) { + this(new Context(params), directory, rpcBindPort, filePrefix); } /** * Creates a new WalletConfig, with the given {@link Context}. Files will be stored in the given directory. */ - private WalletConfig(Context context, File directory, String filePrefix) { + private WalletConfig(Context context, File directory, int rpcBindPort, String filePrefix) { this.context = context; this.params = checkNotNull(context.getParams()); this.directory = checkDir(directory); + this.rpcBindPort = rpcBindPort; this.filePrefix = checkNotNull(filePrefix); } @@ -285,10 +292,10 @@ public class WalletConfig extends AbstractIdleService { // Meant to be overridden by subclasses } - public MoneroWalletRpc createWallet(MoneroWalletConfig config) { + public MoneroWalletRpc createWallet(MoneroWalletConfig config, Integer port) { // start monero-wallet-rpc instance - MoneroWalletRpc walletRpc = startWalletRpcInstance(); + MoneroWalletRpc walletRpc = startWalletRpcInstance(port); // create wallet try { @@ -302,10 +309,10 @@ public class WalletConfig extends AbstractIdleService { } } - public MoneroWalletRpc openWallet(MoneroWalletConfig config) { + public MoneroWalletRpc openWallet(MoneroWalletConfig config, Integer port) { // start monero-wallet-rpc instance - MoneroWalletRpc walletRpc = startWalletRpcInstance(); + MoneroWalletRpc walletRpc = startWalletRpcInstance(port); // open wallet try { @@ -319,13 +326,13 @@ public class WalletConfig extends AbstractIdleService { } } - private MoneroWalletRpc startWalletRpcInstance() { + private MoneroWalletRpc startWalletRpcInstance(Integer port) { // check if monero-wallet-rpc exists if (!new File(MONERO_WALLET_RPC_PATH).exists()) throw new Error("monero-wallet-rpc executable doesn't exist at path " + MONERO_WALLET_RPC_PATH + "; copy monero-wallet-rpc to the project root or set WalletConfig.java MONERO_WALLET_RPC_PATH for your system"); // start monero-wallet-rpc instance and return connected client - return WalletConfig.MONERO_WALLET_RPC_MANAGER.startInstance(Arrays.asList( + List cmd = new ArrayList<>(Arrays.asList( // modifiable list MONERO_WALLET_RPC_PATH, "--" + MONERO_NETWORK_TYPE.toString().toLowerCase(), "--daemon-address", MONERO_DAEMON_URI, @@ -333,6 +340,11 @@ public class WalletConfig extends AbstractIdleService { "--rpc-login", MONERO_WALLET_RPC_USERNAME + ":" + MONERO_WALLET_RPC_PASSWORD, "--wallet-dir", directory.toString() )); + if (port != null && port > 0) { + cmd.add("--rpc-bind-port"); + cmd.add(Integer.toString(port)); + } + return WalletConfig.MONERO_WALLET_RPC_MANAGER.startInstance(cmd); } public void closeWallet(MoneroWallet walletRpc) { @@ -346,7 +358,7 @@ public class WalletConfig extends AbstractIdleService { try { File chainFile = new File(directory, filePrefix + ".spvchain"); boolean chainFileExists = chainFile.exists(); - + // XMR daemon vXmrDaemon = new MoneroDaemonRpc(MONERO_DAEMON_URI, MONERO_DAEMON_USERNAME, MONERO_DAEMON_PASSWORD); @@ -354,9 +366,9 @@ public class WalletConfig extends AbstractIdleService { String xmrPrefix = "_XMR"; vXmrWalletFile = new File(directory, filePrefix + xmrPrefix); if (MoneroUtils.walletExists(vXmrWalletFile.getPath())) { - vXmrWallet = openWallet(new MoneroWalletConfig().setPath(filePrefix + xmrPrefix).setPassword("abctesting123")); + vXmrWallet = openWallet(new MoneroWalletConfig().setPath(filePrefix + xmrPrefix).setPassword("abctesting123"), rpcBindPort); } else { - vXmrWallet = createWallet(new MoneroWalletConfig().setPath(filePrefix + xmrPrefix).setPassword("abctesting123")); + vXmrWallet = createWallet(new MoneroWalletConfig().setPath(filePrefix + xmrPrefix).setPassword("abctesting123"), rpcBindPort); } System.out.println("Monero wallet path: " + vXmrWallet.getPath()); System.out.println("Monero wallet address: " + vXmrWallet.getPrimaryAddress()); @@ -610,12 +622,11 @@ public class WalletConfig extends AbstractIdleService { return vBtcWallet; } - public MoneroDaemon getXmrDaemon() { checkState(state() == State.STARTING || state() == State.RUNNING, "Cannot call until startup is complete"); return vXmrDaemon; } - + public MoneroWallet getXmrWallet() { checkState(state() == State.STARTING || state() == State.RUNNING, "Cannot call until startup is complete"); return vXmrWallet; diff --git a/core/src/main/java/bisq/core/btc/setup/WalletsSetup.java b/core/src/main/java/bisq/core/btc/setup/WalletsSetup.java index fb4b1dadd7..35c5aafe6a 100644 --- a/core/src/main/java/bisq/core/btc/setup/WalletsSetup.java +++ b/core/src/main/java/bisq/core/btc/setup/WalletsSetup.java @@ -50,9 +50,6 @@ import org.bitcoinj.core.PeerAddress; import org.bitcoinj.core.PeerGroup; import org.bitcoinj.core.RejectMessage; import org.bitcoinj.core.listeners.DownloadProgressTracker; -import org.bitcoinj.params.MainNetParams; -import org.bitcoinj.params.RegTestParams; -import org.bitcoinj.params.TestNet3Params; import org.bitcoinj.utils.Threading; import org.bitcoinj.wallet.DeterministicSeed; import org.bitcoinj.wallet.Wallet; @@ -135,6 +132,7 @@ public class WalletsSetup { private final String userAgent; private final NetworkParameters params; private final File walletDir; + private final int walletRpcBindPort; private final int socks5DiscoverMode; private final IntegerProperty numPeers = new SimpleIntegerProperty(0); private final IntegerProperty chainHeight = new SimpleIntegerProperty(0); @@ -161,6 +159,7 @@ public class WalletsSetup { BtcNodes btcNodes, @Named(Config.USER_AGENT) String userAgent, @Named(Config.WALLET_DIR) File walletDir, + @Named(Config.WALLET_RPC_BIND_PORT) int walletRpcBindPort, @Named(Config.USE_ALL_PROVIDED_NODES) boolean useAllProvidedNodes, @Named(Config.NUM_CONNECTIONS_FOR_BTC) int numConnectionsForBtc, @Named(Config.SOCKS5_DISCOVER_MODE) String socks5DiscoverModeString) { @@ -177,6 +176,7 @@ public class WalletsSetup { this.userAgent = userAgent; this.socks5DiscoverMode = evaluateMode(socks5DiscoverModeString); this.walletDir = walletDir; + this.walletRpcBindPort = walletRpcBindPort; xmrWalletFileName = "haveno_" + config.baseCurrencyNetwork.getCurrencyCode(); params = Config.baseCurrencyNetworkParameters(); @@ -207,9 +207,7 @@ public class WalletsSetup { final Socks5Proxy socks5Proxy = preferences.getUseTorForBitcoinJ() ? socks5ProxyProvider.getSocks5Proxy() : null; log.info("Socks5Proxy for bitcoinj: socks5Proxy=" + socks5Proxy); - walletConfig = new WalletConfig(params, - walletDir, - "haveno") { + walletConfig = new WalletConfig(params, walletDir, walletRpcBindPort, "haveno") { @Override protected void onSetupCompleted() { //We are here in the btcj thread Thread[ STARTING,5,main] diff --git a/core/src/main/java/bisq/core/btc/wallet/XmrWalletService.java b/core/src/main/java/bisq/core/btc/wallet/XmrWalletService.java index 3a0aefbb8d..d66f75fa1f 100644 --- a/core/src/main/java/bisq/core/btc/wallet/XmrWalletService.java +++ b/core/src/main/java/bisq/core/btc/wallet/XmrWalletService.java @@ -92,7 +92,8 @@ public class XmrWalletService { MoneroWallet multisigWallet = null; multisigWallet = walletsSetup.getWalletConfig().createWallet(new MoneroWalletConfig() .setPath(path) - .setPassword("abctesting123")); + .setPassword("abctesting123"), + null); // auto-assign port multisigWallets.put(tradeId, multisigWallet); multisigWallet.startSyncing(5000l); return multisigWallet; @@ -104,7 +105,8 @@ public class XmrWalletService { MoneroWallet multisigWallet = null; multisigWallet = walletsSetup.getWalletConfig().openWallet(new MoneroWalletConfig() .setPath(path) - .setPassword("abctesting123")); + .setPassword("abctesting123"), + null); multisigWallets.put(tradeId, multisigWallet); multisigWallet.startSyncing(5000l); // TODO (woodser): use sync period from config. apps stall if too many multisig wallets and too short sync period return multisigWallet;