add config option to specify wallet rpc bind port

This commit is contained in:
premek 2021-11-15 18:02:58 +01:00 committed by woodser
parent 4000fdc1e5
commit 7d21bdf9f3
7 changed files with 65 additions and 36 deletions

View File

@ -62,7 +62,8 @@ alice-desktop:
--nodePort=5555 \ --nodePort=5555 \
--appName=haveno-XMR_STAGENET_Alice \ --appName=haveno-XMR_STAGENET_Alice \
--apiPassword=apitest \ --apiPassword=apitest \
--apiPort=9999 --apiPort=9999 \
--walletRpcBindPort=38091
alice-daemon: alice-daemon:
./haveno-daemon \ ./haveno-daemon \
@ -72,7 +73,8 @@ alice-daemon:
--nodePort=5555 \ --nodePort=5555 \
--appName=haveno-XMR_STAGENET_Alice \ --appName=haveno-XMR_STAGENET_Alice \
--apiPassword=apitest \ --apiPassword=apitest \
--apiPort=9999 --apiPort=9999 \
--walletRpcBindPort=38091
bob-desktop: bob-desktop:
./haveno-desktop \ ./haveno-desktop \
@ -82,7 +84,8 @@ bob-desktop:
--nodePort=6666 \ --nodePort=6666 \
--appName=haveno-XMR_STAGENET_Bob \ --appName=haveno-XMR_STAGENET_Bob \
--apiPassword=apitest \ --apiPassword=apitest \
--apiPort=10000 --apiPort=10000 \
--walletRpcBindPort=38092
bob-daemon: bob-daemon:
./haveno-daemon \ ./haveno-daemon \
@ -92,7 +95,8 @@ bob-daemon:
--nodePort=6666 \ --nodePort=6666 \
--appName=haveno-XMR_STAGENET_Bob \ --appName=haveno-XMR_STAGENET_Bob \
--apiPassword=apitest \ --apiPassword=apitest \
--apiPort=10000 --apiPort=10000 \
--walletRpcBindPort=38092
monero-shared: monero-shared:
./.localnet/monerod \ ./.localnet/monerod \

View File

@ -73,6 +73,7 @@ public class Config {
public static final String STORAGE_DIR = "storageDir"; public static final String STORAGE_DIR = "storageDir";
public static final String KEY_STORAGE_DIR = "keyStorageDir"; public static final String KEY_STORAGE_DIR = "keyStorageDir";
public static final String WALLET_DIR = "walletDir"; 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 USE_DEV_PRIVILEGE_KEYS = "useDevPrivilegeKeys";
public static final String DUMP_STATISTICS = "dumpStatistics"; public static final String DUMP_STATISTICS = "dumpStatistics";
public static final String IGNORE_DEV_MSG = "ignoreDevMsg"; public static final String IGNORE_DEV_MSG = "ignoreDevMsg";
@ -140,6 +141,7 @@ public class Config {
public final String appName; public final String appName;
public final File userDataDir; public final File userDataDir;
public final File appDataDir; public final File appDataDir;
public final int walletRpcBindPort;
public final int nodePort; public final int nodePort;
public final int maxMemory; public final int maxMemory;
public final String logLevel; public final String logLevel;
@ -272,6 +274,12 @@ public class Config {
.ofType(Integer.class) .ofType(Integer.class)
.defaultsTo(9999); .defaultsTo(9999);
ArgumentAcceptingOptionSpec<Integer> walletRpcBindPortOpt =
parser.accepts(WALLET_RPC_BIND_PORT, "Port to bind the wallet RPC on")
.withRequiredArg()
.ofType(int.class)
.defaultsTo(UNSPECIFIED_PORT);
ArgumentAcceptingOptionSpec<Integer> maxMemoryOpt = ArgumentAcceptingOptionSpec<Integer> maxMemoryOpt =
parser.accepts(MAX_MEMORY, "Max. permitted memory (used only by headless versions)") parser.accepts(MAX_MEMORY, "Max. permitted memory (used only by headless versions)")
.withRequiredArg() .withRequiredArg()
@ -628,6 +636,7 @@ public class Config {
this.helpRequested = options.has(helpOpt); this.helpRequested = options.has(helpOpt);
this.configFile = configFile; this.configFile = configFile;
this.nodePort = options.valueOf(nodePortOpt); this.nodePort = options.valueOf(nodePortOpt);
this.walletRpcBindPort = options.valueOf(walletRpcBindPortOpt);
this.maxMemory = options.valueOf(maxMemoryOpt); this.maxMemory = options.valueOf(maxMemoryOpt);
this.logLevel = options.valueOf(logLevelOpt); this.logLevel = options.valueOf(logLevelOpt);
this.bannedBtcNodes = options.valuesOf(bannedBtcNodesOpt); this.bannedBtcNodes = options.valuesOf(bannedBtcNodesOpt);

View File

@ -44,6 +44,7 @@ import java.util.List;
import static bisq.common.config.Config.PROVIDERS; import static bisq.common.config.Config.PROVIDERS;
import static bisq.common.config.Config.WALLET_DIR; 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; import static com.google.inject.name.Names.named;
public class BitcoinModule extends AppModule { 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(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.BTC_NODES)).to(config.btcNodes);
bindConstant().annotatedWith(named(Config.USER_AGENT)).to(config.userAgent); bindConstant().annotatedWith(named(Config.USER_AGENT)).to(config.userAgent);

View File

@ -9,7 +9,7 @@ import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import lombok.extern.slf4j.Slf4j;
import monero.common.MoneroError; import monero.common.MoneroError;
import monero.wallet.MoneroWalletRpc; import monero.wallet.MoneroWalletRpc;
@ -17,11 +17,13 @@ import monero.wallet.MoneroWalletRpc;
/** /**
* Manages monero-wallet-rpc processes bound to ports. * Manages monero-wallet-rpc processes bound to ports.
*/ */
@Slf4j
public class MoneroWalletRpcManager { 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 Integer startPort;
private Map<Integer, MoneroWalletRpc> registeredPorts = new HashMap<Integer, MoneroWalletRpc>(); private final Map<Integer, MoneroWalletRpc> registeredPorts = new HashMap<>();
/** /**
* Manage monero-wallet-rpc instances by auto-assigning ports. * Manage monero-wallet-rpc instances by auto-assigning ports.
@ -48,8 +50,9 @@ public class MoneroWalletRpcManager {
try { try {
// register given port // register given port
if (cmd.indexOf("--rpc-bind-port") >= 0) { if (cmd.contains(RPC_BIND_PORT_ARGUMENT)) {
int port = Integer.valueOf(cmd.indexOf("--rpc-bind-port") + 1); 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 MoneroWalletRpc walletRpc = new MoneroWalletRpc(cmd); // starts monero-wallet-rpc process
registeredPorts.put(port, walletRpc); registeredPorts.put(port, walletRpc);
return walletRpc; return walletRpc;
@ -59,19 +62,19 @@ public class MoneroWalletRpcManager {
else { else {
int numAttempts = 0; int numAttempts = 0;
while (numAttempts < NUM_ALLOWED_ATTEMPTS) { while (numAttempts < NUM_ALLOWED_ATTEMPTS) {
int port = -1;
try { try {
numAttempts++; numAttempts++;
int port = registerPort(); port = registerPort();
List<String> cmdCopy = new ArrayList<String>(cmd); // preserve original cmd List<String> cmdCopy = new ArrayList<>(cmd); // preserve original cmd
cmdCopy.add("--rpc-bind-port"); cmdCopy.add(RPC_BIND_PORT_ARGUMENT);
cmdCopy.add("" + port); cmdCopy.add("" + port);
System.out.println(cmdCopy);
MoneroWalletRpc walletRpc = new MoneroWalletRpc(cmdCopy); // start monero-wallet-rpc process MoneroWalletRpc walletRpc = new MoneroWalletRpc(cmdCopy); // start monero-wallet-rpc process
registeredPorts.put(port, walletRpc); registeredPorts.put(port, walletRpc);
return walletRpc; return walletRpc;
} catch (Exception e) { } catch (Exception e) {
if (numAttempts >= NUM_ALLOWED_ATTEMPTS) { 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; throw e;
} }
} }

View File

@ -71,7 +71,9 @@ import java.io.FileInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import org.slf4j.Logger; import org.slf4j.Logger;
@ -144,6 +146,7 @@ public class WalletConfig extends AbstractIdleService {
protected volatile Wallet vBtcWallet; protected volatile Wallet vBtcWallet;
protected volatile PeerGroup vPeerGroup; protected volatile PeerGroup vPeerGroup;
protected final int rpcBindPort;
protected final File directory; protected final File directory;
protected volatile File vXmrWalletFile; protected volatile File vXmrWalletFile;
protected volatile File vBtcWalletFile; 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. * 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) { public WalletConfig(NetworkParameters params,
this(new Context(params), directory, filePrefix); 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. * 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.context = context;
this.params = checkNotNull(context.getParams()); this.params = checkNotNull(context.getParams());
this.directory = checkDir(directory); this.directory = checkDir(directory);
this.rpcBindPort = rpcBindPort;
this.filePrefix = checkNotNull(filePrefix); this.filePrefix = checkNotNull(filePrefix);
} }
@ -285,10 +292,10 @@ public class WalletConfig extends AbstractIdleService {
// Meant to be overridden by subclasses // Meant to be overridden by subclasses
} }
public MoneroWalletRpc createWallet(MoneroWalletConfig config) { public MoneroWalletRpc createWallet(MoneroWalletConfig config, Integer port) {
// start monero-wallet-rpc instance // start monero-wallet-rpc instance
MoneroWalletRpc walletRpc = startWalletRpcInstance(); MoneroWalletRpc walletRpc = startWalletRpcInstance(port);
// create wallet // create wallet
try { 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 // start monero-wallet-rpc instance
MoneroWalletRpc walletRpc = startWalletRpcInstance(); MoneroWalletRpc walletRpc = startWalletRpcInstance(port);
// open wallet // open wallet
try { try {
@ -319,13 +326,13 @@ public class WalletConfig extends AbstractIdleService {
} }
} }
private MoneroWalletRpc startWalletRpcInstance() { private MoneroWalletRpc startWalletRpcInstance(Integer port) {
// check if monero-wallet-rpc exists // 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"); 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 // start monero-wallet-rpc instance and return connected client
return WalletConfig.MONERO_WALLET_RPC_MANAGER.startInstance(Arrays.asList( List<String> cmd = new ArrayList<>(Arrays.asList( // modifiable list
MONERO_WALLET_RPC_PATH, MONERO_WALLET_RPC_PATH,
"--" + MONERO_NETWORK_TYPE.toString().toLowerCase(), "--" + MONERO_NETWORK_TYPE.toString().toLowerCase(),
"--daemon-address", MONERO_DAEMON_URI, "--daemon-address", MONERO_DAEMON_URI,
@ -333,6 +340,11 @@ public class WalletConfig extends AbstractIdleService {
"--rpc-login", MONERO_WALLET_RPC_USERNAME + ":" + MONERO_WALLET_RPC_PASSWORD, "--rpc-login", MONERO_WALLET_RPC_USERNAME + ":" + MONERO_WALLET_RPC_PASSWORD,
"--wallet-dir", directory.toString() "--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) { public void closeWallet(MoneroWallet walletRpc) {
@ -346,7 +358,7 @@ public class WalletConfig extends AbstractIdleService {
try { try {
File chainFile = new File(directory, filePrefix + ".spvchain"); File chainFile = new File(directory, filePrefix + ".spvchain");
boolean chainFileExists = chainFile.exists(); boolean chainFileExists = chainFile.exists();
// XMR daemon // XMR daemon
vXmrDaemon = new MoneroDaemonRpc(MONERO_DAEMON_URI, MONERO_DAEMON_USERNAME, MONERO_DAEMON_PASSWORD); vXmrDaemon = new MoneroDaemonRpc(MONERO_DAEMON_URI, MONERO_DAEMON_USERNAME, MONERO_DAEMON_PASSWORD);
@ -354,9 +366,9 @@ public class WalletConfig extends AbstractIdleService {
String xmrPrefix = "_XMR"; String xmrPrefix = "_XMR";
vXmrWalletFile = new File(directory, filePrefix + xmrPrefix); vXmrWalletFile = new File(directory, filePrefix + xmrPrefix);
if (MoneroUtils.walletExists(vXmrWalletFile.getPath())) { 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 { } 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 path: " + vXmrWallet.getPath());
System.out.println("Monero wallet address: " + vXmrWallet.getPrimaryAddress()); System.out.println("Monero wallet address: " + vXmrWallet.getPrimaryAddress());
@ -610,12 +622,11 @@ public class WalletConfig extends AbstractIdleService {
return vBtcWallet; return vBtcWallet;
} }
public MoneroDaemon getXmrDaemon() { public MoneroDaemon getXmrDaemon() {
checkState(state() == State.STARTING || state() == State.RUNNING, "Cannot call until startup is complete"); checkState(state() == State.STARTING || state() == State.RUNNING, "Cannot call until startup is complete");
return vXmrDaemon; return vXmrDaemon;
} }
public MoneroWallet getXmrWallet() { public MoneroWallet getXmrWallet() {
checkState(state() == State.STARTING || state() == State.RUNNING, "Cannot call until startup is complete"); checkState(state() == State.STARTING || state() == State.RUNNING, "Cannot call until startup is complete");
return vXmrWallet; return vXmrWallet;

View File

@ -50,9 +50,6 @@ import org.bitcoinj.core.PeerAddress;
import org.bitcoinj.core.PeerGroup; import org.bitcoinj.core.PeerGroup;
import org.bitcoinj.core.RejectMessage; import org.bitcoinj.core.RejectMessage;
import org.bitcoinj.core.listeners.DownloadProgressTracker; 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.utils.Threading;
import org.bitcoinj.wallet.DeterministicSeed; import org.bitcoinj.wallet.DeterministicSeed;
import org.bitcoinj.wallet.Wallet; import org.bitcoinj.wallet.Wallet;
@ -135,6 +132,7 @@ public class WalletsSetup {
private final String userAgent; private final String userAgent;
private final NetworkParameters params; private final NetworkParameters params;
private final File walletDir; private final File walletDir;
private final int walletRpcBindPort;
private final int socks5DiscoverMode; private final int socks5DiscoverMode;
private final IntegerProperty numPeers = new SimpleIntegerProperty(0); private final IntegerProperty numPeers = new SimpleIntegerProperty(0);
private final IntegerProperty chainHeight = new SimpleIntegerProperty(0); private final IntegerProperty chainHeight = new SimpleIntegerProperty(0);
@ -161,6 +159,7 @@ public class WalletsSetup {
BtcNodes btcNodes, BtcNodes btcNodes,
@Named(Config.USER_AGENT) String userAgent, @Named(Config.USER_AGENT) String userAgent,
@Named(Config.WALLET_DIR) File walletDir, @Named(Config.WALLET_DIR) File walletDir,
@Named(Config.WALLET_RPC_BIND_PORT) int walletRpcBindPort,
@Named(Config.USE_ALL_PROVIDED_NODES) boolean useAllProvidedNodes, @Named(Config.USE_ALL_PROVIDED_NODES) boolean useAllProvidedNodes,
@Named(Config.NUM_CONNECTIONS_FOR_BTC) int numConnectionsForBtc, @Named(Config.NUM_CONNECTIONS_FOR_BTC) int numConnectionsForBtc,
@Named(Config.SOCKS5_DISCOVER_MODE) String socks5DiscoverModeString) { @Named(Config.SOCKS5_DISCOVER_MODE) String socks5DiscoverModeString) {
@ -177,6 +176,7 @@ public class WalletsSetup {
this.userAgent = userAgent; this.userAgent = userAgent;
this.socks5DiscoverMode = evaluateMode(socks5DiscoverModeString); this.socks5DiscoverMode = evaluateMode(socks5DiscoverModeString);
this.walletDir = walletDir; this.walletDir = walletDir;
this.walletRpcBindPort = walletRpcBindPort;
xmrWalletFileName = "haveno_" + config.baseCurrencyNetwork.getCurrencyCode(); xmrWalletFileName = "haveno_" + config.baseCurrencyNetwork.getCurrencyCode();
params = Config.baseCurrencyNetworkParameters(); params = Config.baseCurrencyNetworkParameters();
@ -207,9 +207,7 @@ public class WalletsSetup {
final Socks5Proxy socks5Proxy = preferences.getUseTorForBitcoinJ() ? socks5ProxyProvider.getSocks5Proxy() : null; final Socks5Proxy socks5Proxy = preferences.getUseTorForBitcoinJ() ? socks5ProxyProvider.getSocks5Proxy() : null;
log.info("Socks5Proxy for bitcoinj: socks5Proxy=" + socks5Proxy); log.info("Socks5Proxy for bitcoinj: socks5Proxy=" + socks5Proxy);
walletConfig = new WalletConfig(params, walletConfig = new WalletConfig(params, walletDir, walletRpcBindPort, "haveno") {
walletDir,
"haveno") {
@Override @Override
protected void onSetupCompleted() { protected void onSetupCompleted() {
//We are here in the btcj thread Thread[ STARTING,5,main] //We are here in the btcj thread Thread[ STARTING,5,main]

View File

@ -92,7 +92,8 @@ public class XmrWalletService {
MoneroWallet multisigWallet = null; MoneroWallet multisigWallet = null;
multisigWallet = walletsSetup.getWalletConfig().createWallet(new MoneroWalletConfig() multisigWallet = walletsSetup.getWalletConfig().createWallet(new MoneroWalletConfig()
.setPath(path) .setPath(path)
.setPassword("abctesting123")); .setPassword("abctesting123"),
null); // auto-assign port
multisigWallets.put(tradeId, multisigWallet); multisigWallets.put(tradeId, multisigWallet);
multisigWallet.startSyncing(5000l); multisigWallet.startSyncing(5000l);
return multisigWallet; return multisigWallet;
@ -104,7 +105,8 @@ public class XmrWalletService {
MoneroWallet multisigWallet = null; MoneroWallet multisigWallet = null;
multisigWallet = walletsSetup.getWalletConfig().openWallet(new MoneroWalletConfig() multisigWallet = walletsSetup.getWalletConfig().openWallet(new MoneroWalletConfig()
.setPath(path) .setPath(path)
.setPassword("abctesting123")); .setPassword("abctesting123"),
null);
multisigWallets.put(tradeId, multisigWallet); 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 multisigWallet.startSyncing(5000l); // TODO (woodser): use sync period from config. apps stall if too many multisig wallets and too short sync period
return multisigWallet; return multisigWallet;