mirror of
https://github.com/haveno-dex/haveno.git
synced 2024-11-17 00:07:49 +00:00
app fully initialized before daemon connection or wallet by default
wallet initializes when first connected to get correct height connect to local node if available and last connection offline use only one internal daemon in monero node service
This commit is contained in:
parent
9dfbb0d5a6
commit
fdddc87477
6 changed files with 176 additions and 140 deletions
|
@ -268,15 +268,9 @@ public final class CoreMoneroConnectionsService {
|
||||||
addConnection(connection);
|
addConnection(connection);
|
||||||
}
|
}
|
||||||
|
|
||||||
// restore last used connection
|
// restore last used connection if present
|
||||||
var currentConnection = connectionList.getCurrentConnectionUri();
|
var currentConnectionUri = connectionList.getCurrentConnectionUri();
|
||||||
currentConnection.ifPresentOrElse(connectionManager::setConnection, () -> {
|
if (currentConnectionUri.isPresent()) connectionManager.setConnection(currentConnectionUri.get());
|
||||||
connectionManager.setConnection(DEFAULT_CONNECTIONS.get(0).getUri()); // default to localhost
|
|
||||||
});
|
|
||||||
|
|
||||||
// initialize daemon
|
|
||||||
daemon = new MoneroDaemonRpc(connectionManager.getConnection());
|
|
||||||
updateDaemonInfo();
|
|
||||||
|
|
||||||
// restore configuration
|
// restore configuration
|
||||||
connectionManager.setAutoSwitch(connectionList.getAutoSwitch());
|
connectionManager.setAutoSwitch(connectionList.getAutoSwitch());
|
||||||
|
@ -288,11 +282,15 @@ public final class CoreMoneroConnectionsService {
|
||||||
// run once
|
// run once
|
||||||
if (!isInitialized) {
|
if (!isInitialized) {
|
||||||
|
|
||||||
// initialize local monero node
|
// register connection change listener
|
||||||
|
connectionManager.addListener(this::onConnectionChanged);
|
||||||
|
|
||||||
|
// register local node listener
|
||||||
nodeService.addListener(new MoneroNodeServiceListener() {
|
nodeService.addListener(new MoneroNodeServiceListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onNodeStarted(MoneroDaemonRpc daemon) {
|
public void onNodeStarted(MoneroDaemonRpc daemon) {
|
||||||
log.info(getClass() + ".onNodeStarted() called");
|
log.info(getClass() + ".onNodeStarted() called");
|
||||||
|
daemon.getRpcConnection().checkConnection(connectionManager.getTimeout());
|
||||||
setConnection(daemon.getRpcConnection());
|
setConnection(daemon.getRpcConnection());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -303,10 +301,10 @@ public final class CoreMoneroConnectionsService {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// start local node if the last connection is local and not running
|
// start local node if last connection is local and offline
|
||||||
currentConnection.ifPresent(connection -> {
|
currentConnectionUri.ifPresent(uri -> {
|
||||||
try {
|
try {
|
||||||
if (nodeService.isMoneroNodeConnection(connection) && !nodeService.isMoneroNodeRunning()) {
|
if (CoreMoneroNodeService.isLocalHost(uri) && !nodeService.isMoneroNodeRunning()) {
|
||||||
nodeService.startMoneroNode();
|
nodeService.startMoneroNode();
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
@ -314,13 +312,22 @@ public final class CoreMoneroConnectionsService {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// register connection change listener
|
|
||||||
connectionManager.addListener(this::onConnectionChanged);
|
|
||||||
|
|
||||||
// poll daemon periodically
|
// poll daemon periodically
|
||||||
startPollingDaemon();
|
startPollingDaemon();
|
||||||
isInitialized = true;
|
isInitialized = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if offline, connect to local node if available
|
||||||
|
if (!connectionManager.isConnected() && nodeService.isMoneroNodeRunning()) {
|
||||||
|
MoneroRpcConnection connection = connectionManager.getConnectionByUri(nodeService.getDaemon().getRpcConnection().getUri());
|
||||||
|
if (connection == null) connection = nodeService.getDaemon().getRpcConnection();
|
||||||
|
connection.checkConnection(connectionManager.getTimeout());
|
||||||
|
setConnection(connection);
|
||||||
|
}
|
||||||
|
|
||||||
|
// set the daemon based on the connection
|
||||||
|
if (getConnection() != null) daemon = new MoneroDaemonRpc(connectionManager.getConnection());
|
||||||
|
updateDaemonInfo();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -36,17 +36,17 @@ import java.util.List;
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
import monero.common.MoneroRpcConnection;
|
|
||||||
import monero.daemon.MoneroDaemonRpc;
|
import monero.daemon.MoneroDaemonRpc;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Manages a Monero node instance or connection to an instance.
|
* Start and stop or connect to a local Monero node.
|
||||||
*/
|
*/
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Singleton
|
@Singleton
|
||||||
public class CoreMoneroNodeService {
|
public class CoreMoneroNodeService {
|
||||||
|
|
||||||
public static final String LOCAL_NODE_ADDRESS = "127.0.0.1"; // expected connection from local MoneroDaemonRpc
|
private static final String LOOPBACK_HOST = "127.0.0.1"; // local loopback address to host Monero node
|
||||||
|
private static final String LOCALHOST = "localhost";
|
||||||
private static final String MONERO_NETWORK_TYPE = Config.baseCurrencyNetwork().getNetwork().toLowerCase();
|
private static final String MONERO_NETWORK_TYPE = Config.baseCurrencyNetwork().getNetwork().toLowerCase();
|
||||||
private static final String MONEROD_PATH = System.getProperty("user.dir") + File.separator + ".localnet" + File.separator + "monerod";
|
private static final String MONEROD_PATH = System.getProperty("user.dir") + File.separator + ".localnet" + File.separator + "monerod";
|
||||||
private static final String MONEROD_DATADIR = System.getProperty("user.dir") + File.separator + ".localnet" + File.separator + MONERO_NETWORK_TYPE;
|
private static final String MONEROD_DATADIR = System.getProperty("user.dir") + File.separator + ".localnet" + File.separator + MONERO_NETWORK_TYPE;
|
||||||
|
@ -63,15 +63,11 @@ public class CoreMoneroNodeService {
|
||||||
"--rpc-login", "superuser:abctesting123" // TODO: remove authentication
|
"--rpc-login", "superuser:abctesting123" // TODO: remove authentication
|
||||||
);
|
);
|
||||||
|
|
||||||
// local monero node owned by this process
|
// client to the local Monero node
|
||||||
private MoneroDaemonRpc daemon;
|
private MoneroDaemonRpc daemon;
|
||||||
|
|
||||||
// local monero node for detecting running node not owned by this process
|
|
||||||
private MoneroDaemonRpc defaultMoneroDaemon;
|
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public CoreMoneroNodeService(Preferences preferences) {
|
public CoreMoneroNodeService(Preferences preferences) {
|
||||||
this.daemon = null;
|
|
||||||
this.preferences = preferences;
|
this.preferences = preferences;
|
||||||
int rpcPort = 18081; // mainnet
|
int rpcPort = 18081; // mainnet
|
||||||
if (Config.baseCurrencyNetwork().isTestnet()) {
|
if (Config.baseCurrencyNetwork().isTestnet()) {
|
||||||
|
@ -79,9 +75,15 @@ public class CoreMoneroNodeService {
|
||||||
} else if (Config.baseCurrencyNetwork().isStagenet()) {
|
} else if (Config.baseCurrencyNetwork().isStagenet()) {
|
||||||
rpcPort = 38081;
|
rpcPort = 38081;
|
||||||
}
|
}
|
||||||
// TODO: remove authentication
|
this.daemon = new MoneroDaemonRpc("http://" + LOOPBACK_HOST + ":" + rpcPort, "superuser", "abctesting123"); // TODO: remove authentication
|
||||||
var defaultMoneroConnection = new MoneroRpcConnection("http://" + LOCAL_NODE_ADDRESS + ":" + rpcPort, "superuser", "abctesting123").setPriority(1); // localhost is first priority
|
}
|
||||||
defaultMoneroDaemon = new MoneroDaemonRpc(defaultMoneroConnection);
|
|
||||||
|
/**
|
||||||
|
* Returns whether the given URI is on local host. // TODO: move to utils
|
||||||
|
*/
|
||||||
|
public static boolean isLocalHost(String uri) throws URISyntaxException {
|
||||||
|
String host = new URI(uri).getHost();
|
||||||
|
return host.equals(CoreMoneroNodeService.LOOPBACK_HOST) || host.equals(CoreMoneroNodeService.LOCALHOST);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addListener(MoneroNodeServiceListener listener) {
|
public void addListener(MoneroNodeServiceListener listener) {
|
||||||
|
@ -93,18 +95,17 @@ public class CoreMoneroNodeService {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns whether a connection string URI is a local monero node.
|
* Returns the client of the local monero node.
|
||||||
*/
|
*/
|
||||||
public boolean isMoneroNodeConnection(String connection) throws URISyntaxException {
|
public MoneroDaemonRpc getDaemon() {
|
||||||
var uri = new URI(connection);
|
return daemon;
|
||||||
return CoreMoneroNodeService.LOCAL_NODE_ADDRESS.equals(uri.getHost());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns whether the local monero node is running or local daemon connection is running
|
* Returns whether a local monero node is running.
|
||||||
*/
|
*/
|
||||||
public boolean isMoneroNodeRunning() {
|
public boolean isMoneroNodeRunning() {
|
||||||
return daemon != null || defaultMoneroDaemon.isConnected();
|
return daemon.isConnected();
|
||||||
}
|
}
|
||||||
|
|
||||||
public MoneroNodeSettings getMoneroNodeSettings() {
|
public MoneroNodeSettings getMoneroNodeSettings() {
|
||||||
|
@ -124,7 +125,7 @@ public class CoreMoneroNodeService {
|
||||||
* Persists the settings to preferences if the node started successfully.
|
* Persists the settings to preferences if the node started successfully.
|
||||||
*/
|
*/
|
||||||
public void startMoneroNode(MoneroNodeSettings settings) throws IOException {
|
public void startMoneroNode(MoneroNodeSettings settings) throws IOException {
|
||||||
if (isMoneroNodeRunning()) throw new IllegalStateException("Monero node already running");
|
if (isMoneroNodeRunning()) throw new IllegalStateException("Local Monero node already running");
|
||||||
|
|
||||||
log.info("Starting local Monero node: " + settings);
|
log.info("Starting local Monero node: " + settings);
|
||||||
|
|
||||||
|
@ -146,23 +147,19 @@ public class CoreMoneroNodeService {
|
||||||
args.addAll(flags);
|
args.addAll(flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
daemon = new MoneroDaemonRpc(args);
|
daemon = new MoneroDaemonRpc(args); // start daemon as process and re-assign client
|
||||||
preferences.setMoneroNodeSettings(settings);
|
preferences.setMoneroNodeSettings(settings);
|
||||||
for (var listener : listeners) listener.onNodeStarted(daemon);
|
for (var listener : listeners) listener.onNodeStarted(daemon);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stops the current local monero node if owned by this process.
|
* Stops the current local monero node if we own its process.
|
||||||
* Does not remove the last MoneroNodeSettings.
|
* Does not remove the last MoneroNodeSettings.
|
||||||
*/
|
*/
|
||||||
public void stopMoneroNode() {
|
public void stopMoneroNode() {
|
||||||
if (!isMoneroNodeRunning()) throw new IllegalStateException("Monero node is not running");
|
if (!isMoneroNodeRunning()) throw new IllegalStateException("Local Monero node is not running");
|
||||||
if (daemon != null) {
|
if (daemon.getProcess() == null || !daemon.getProcess().isAlive()) throw new IllegalStateException("Cannot stop local Monero node because we don't own its process"); // TODO (woodser): remove isAlive() check after monero-java 0.5.4 which nullifies internal process
|
||||||
daemon.stopProcess();
|
daemon.stopProcess();
|
||||||
daemon = null;
|
|
||||||
for (var listener : listeners) listener.onNodeStopped();
|
for (var listener : listeners) listener.onNodeStopped();
|
||||||
} else {
|
|
||||||
defaultMoneroDaemon.stopProcess(); // throws MoneroError
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -79,7 +79,7 @@ public class AppStartupState {
|
||||||
if (a && b && c) {
|
if (a && b && c) {
|
||||||
walletAndNetworkReady.set(true);
|
walletAndNetworkReady.set(true);
|
||||||
}
|
}
|
||||||
return a && b && c && d;
|
return a && d; // app fully initialized before daemon connection and wallet by default
|
||||||
});
|
});
|
||||||
p2pNetworkAndWalletInitialized.subscribe((observable, oldValue, newValue) -> {
|
p2pNetworkAndWalletInitialized.subscribe((observable, oldValue, newValue) -> {
|
||||||
if (newValue) {
|
if (newValue) {
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
|
|
||||||
package bisq.core.app;
|
package bisq.core.app;
|
||||||
|
|
||||||
|
import bisq.common.UserThread;
|
||||||
import bisq.core.api.CoreMoneroConnectionsService;
|
import bisq.core.api.CoreMoneroConnectionsService;
|
||||||
import bisq.core.locale.Res;
|
import bisq.core.locale.Res;
|
||||||
import bisq.core.provider.price.PriceFeedService;
|
import bisq.core.provider.price.PriceFeedService;
|
||||||
|
@ -109,7 +110,7 @@ public class P2PNetworkSetup {
|
||||||
return result;
|
return result;
|
||||||
});
|
});
|
||||||
p2PNetworkInfoBinding.subscribe((observable, oldValue, newValue) -> {
|
p2PNetworkInfoBinding.subscribe((observable, oldValue, newValue) -> {
|
||||||
p2PNetworkInfo.set(newValue);
|
UserThread.execute(() -> p2PNetworkInfo.set(newValue));
|
||||||
});
|
});
|
||||||
|
|
||||||
bootstrapState.set(Res.get("mainView.bootstrapState.connectionToTorNetwork"));
|
bootstrapState.set(Res.get("mainView.bootstrapState.connectionToTorNetwork"));
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
package bisq.core.btc;
|
package bisq.core.btc;
|
||||||
|
|
||||||
import bisq.common.UserThread;
|
import bisq.common.UserThread;
|
||||||
|
import bisq.core.btc.listeners.XmrBalanceListener;
|
||||||
import bisq.core.btc.wallet.XmrWalletService;
|
import bisq.core.btc.wallet.XmrWalletService;
|
||||||
import bisq.core.offer.OfferPayload;
|
import bisq.core.offer.OfferPayload;
|
||||||
import bisq.core.offer.OpenOffer;
|
import bisq.core.offer.OpenOffer;
|
||||||
|
@ -41,7 +42,6 @@ import lombok.Getter;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import monero.wallet.model.MoneroOutputQuery;
|
import monero.wallet.model.MoneroOutputQuery;
|
||||||
import monero.wallet.model.MoneroOutputWallet;
|
import monero.wallet.model.MoneroOutputWallet;
|
||||||
import monero.wallet.model.MoneroWalletListener;
|
|
||||||
import org.bitcoinj.core.Coin;
|
import org.bitcoinj.core.Coin;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
|
@ -80,18 +80,19 @@ public class Balances {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onAllServicesInitialized() {
|
public void onAllServicesInitialized() {
|
||||||
openOfferManager.getObservableList().addListener((ListChangeListener<OpenOffer>) c -> updateBalance());
|
openOfferManager.getObservableList().addListener((ListChangeListener<OpenOffer>) c -> updatedBalances());
|
||||||
tradeManager.getObservableList().addListener((ListChangeListener<Trade>) change -> updateBalance());
|
tradeManager.getObservableList().addListener((ListChangeListener<Trade>) change -> updatedBalances());
|
||||||
refundManager.getDisputesAsObservableList().addListener((ListChangeListener<Dispute>) c -> updateBalance());
|
refundManager.getDisputesAsObservableList().addListener((ListChangeListener<Dispute>) c -> updatedBalances());
|
||||||
xmrWalletService.getWallet().addListener(new MoneroWalletListener() {
|
xmrWalletService.addBalanceListener(new XmrBalanceListener() {
|
||||||
@Override public void onBalancesChanged(BigInteger newBalance, BigInteger newUnlockedBalance) { updateBalance(); }
|
@Override
|
||||||
@Override public void onOutputReceived(MoneroOutputWallet output) { updateBalance(); }
|
public void onBalanceChanged(BigInteger balance) {
|
||||||
@Override public void onOutputSpent(MoneroOutputWallet output) { updateBalance(); }
|
updatedBalances();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
updateBalance();
|
updatedBalances();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateBalance() {
|
private void updatedBalances() {
|
||||||
// Need to delay a bit to get the balances correct
|
// Need to delay a bit to get the balances correct
|
||||||
UserThread.execute(() -> {
|
UserThread.execute(() -> {
|
||||||
updateAvailableBalance();
|
updateAvailableBalance();
|
||||||
|
@ -105,19 +106,21 @@ public class Balances {
|
||||||
// TODO (woodser): balances being set as Coin from BigInteger.longValue(), which can lose precision. should be in centineros for consistency with the rest of the application
|
// TODO (woodser): balances being set as Coin from BigInteger.longValue(), which can lose precision. should be in centineros for consistency with the rest of the application
|
||||||
|
|
||||||
private void updateAvailableBalance() {
|
private void updateAvailableBalance() {
|
||||||
availableBalance.set(Coin.valueOf(xmrWalletService.getWallet().getUnlockedBalance(0).longValueExact()));
|
availableBalance.set(Coin.valueOf(xmrWalletService.getWallet() == null ? 0 : xmrWalletService.getWallet().getUnlockedBalance(0).longValueExact()));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateLockedBalance() {
|
private void updateLockedBalance() {
|
||||||
BigInteger balance = xmrWalletService.getWallet().getBalance(0);
|
BigInteger balance = xmrWalletService.getWallet() == null ? new BigInteger("0") : xmrWalletService.getWallet().getBalance(0);
|
||||||
BigInteger unlockedBalance = xmrWalletService.getWallet().getUnlockedBalance(0);
|
BigInteger unlockedBalance = xmrWalletService.getWallet() == null ? new BigInteger("0") : xmrWalletService.getWallet().getUnlockedBalance(0);
|
||||||
lockedBalance.set(Coin.valueOf(balance.subtract(unlockedBalance).longValueExact()));
|
lockedBalance.set(Coin.valueOf(balance.subtract(unlockedBalance).longValueExact()));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateReservedOfferBalance() {
|
private void updateReservedOfferBalance() {
|
||||||
Coin sum = Coin.valueOf(0);
|
Coin sum = Coin.valueOf(0);
|
||||||
|
if (xmrWalletService.getWallet() != null) {
|
||||||
List<MoneroOutputWallet> frozenOutputs = xmrWalletService.getWallet().getOutputs(new MoneroOutputQuery().setIsFrozen(true).setIsSpent(false));
|
List<MoneroOutputWallet> frozenOutputs = xmrWalletService.getWallet().getOutputs(new MoneroOutputQuery().setIsFrozen(true).setIsSpent(false));
|
||||||
for (MoneroOutputWallet frozenOutput : frozenOutputs) sum = sum.add(Coin.valueOf(frozenOutput.getAmount().longValueExact()));
|
for (MoneroOutputWallet frozenOutput : frozenOutputs) sum = sum.add(Coin.valueOf(frozenOutput.getAmount().longValueExact()));
|
||||||
|
}
|
||||||
reservedOfferBalance.set(sum);
|
reservedOfferBalance.set(sum);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -76,7 +76,7 @@ public class XmrWalletService {
|
||||||
protected final CopyOnWriteArraySet<MoneroWalletListenerI> walletListeners = new CopyOnWriteArraySet<>();
|
protected final CopyOnWriteArraySet<MoneroWalletListenerI> walletListeners = new CopyOnWriteArraySet<>();
|
||||||
|
|
||||||
private TradeManager tradeManager;
|
private TradeManager tradeManager;
|
||||||
private MoneroWallet wallet;
|
private MoneroWalletRpc wallet;
|
||||||
private Map<String, MoneroWallet> multisigWallets;
|
private Map<String, MoneroWallet> multisigWallets;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
|
@ -159,64 +159,6 @@ public class XmrWalletService {
|
||||||
return new File(path + ".keys").exists();
|
return new File(path + ".keys").exists();
|
||||||
}
|
}
|
||||||
|
|
||||||
public MoneroWalletRpc createWallet(MoneroWalletConfig config, Integer port) {
|
|
||||||
|
|
||||||
// start monero-wallet-rpc instance
|
|
||||||
MoneroWalletRpc walletRpc = startWalletRpcInstance(port);
|
|
||||||
|
|
||||||
// create wallet
|
|
||||||
try {
|
|
||||||
walletRpc.createWallet(config);
|
|
||||||
walletRpc.startSyncing(MONERO_WALLET_SYNC_RATE);
|
|
||||||
return walletRpc;
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
MONERO_WALLET_RPC_MANAGER.stopInstance(walletRpc, false);
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public MoneroWalletRpc openWallet(MoneroWalletConfig config, Integer port) {
|
|
||||||
|
|
||||||
// start monero-wallet-rpc instance
|
|
||||||
MoneroWalletRpc walletRpc = startWalletRpcInstance(port);
|
|
||||||
|
|
||||||
// open wallet
|
|
||||||
try {
|
|
||||||
walletRpc.openWallet(config);
|
|
||||||
walletRpc.startSyncing(MONERO_WALLET_SYNC_RATE);
|
|
||||||
return walletRpc;
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
MONERO_WALLET_RPC_MANAGER.stopInstance(walletRpc, false);
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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");
|
|
||||||
|
|
||||||
// get app's current daemon connection
|
|
||||||
MoneroRpcConnection connection = connectionsService.getConnection();
|
|
||||||
|
|
||||||
// start monero-wallet-rpc instance and return connected client
|
|
||||||
List<String> cmd = new ArrayList<>(Arrays.asList( // modifiable list
|
|
||||||
MONERO_WALLET_RPC_PATH, "--" + MONERO_NETWORK_TYPE.toString().toLowerCase(), "--daemon-address", connection.getUri(), "--rpc-login",
|
|
||||||
MONERO_WALLET_RPC_USERNAME + ":" + getWalletPassword(), "--wallet-dir", walletDir.toString()));
|
|
||||||
if (connection.getUsername() != null) {
|
|
||||||
cmd.add("--daemon-login");
|
|
||||||
cmd.add(connection.getUsername() + ":" + connection.getPassword());
|
|
||||||
}
|
|
||||||
if (port != null && port > 0) {
|
|
||||||
cmd.add("--rpc-bind-port");
|
|
||||||
cmd.add(Integer.toString(port));
|
|
||||||
}
|
|
||||||
return MONERO_WALLET_RPC_MANAGER.startInstance(cmd);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void closeWallet(MoneroWallet walletRpc, boolean save) {
|
public void closeWallet(MoneroWallet walletRpc, boolean save) {
|
||||||
log.info("{}.closeWallet({}, {})", getClass(), walletRpc.getPath(), save);
|
log.info("{}.closeWallet({}, {})", getClass(), walletRpc.getPath(), save);
|
||||||
MONERO_WALLET_RPC_MANAGER.stopInstance((MoneroWalletRpc) walletRpc, save);
|
MONERO_WALLET_RPC_MANAGER.stopInstance((MoneroWalletRpc) walletRpc, save);
|
||||||
|
@ -290,22 +232,39 @@ public class XmrWalletService {
|
||||||
// backup wallet files
|
// backup wallet files
|
||||||
backupWallets();
|
backupWallets();
|
||||||
|
|
||||||
// initialize main wallet
|
// initialize main wallet if connected or previously created
|
||||||
MoneroWalletConfig walletConfig = new MoneroWalletConfig().setPath(MONERO_WALLET_NAME).setPassword(getWalletPassword());
|
tryInitMainWallet();
|
||||||
wallet = MoneroUtils.walletExists(xmrWalletFile.getPath()) ? openWallet(walletConfig, rpcBindPort) : createWallet(walletConfig, rpcBindPort);
|
|
||||||
System.out.println("Monero wallet path: " + wallet.getPath());
|
|
||||||
System.out.println("Monero wallet address: " + wallet.getPrimaryAddress());
|
|
||||||
System.out.println("Monero wallet uri: " + ((MoneroWalletRpc) wallet).getRpcConnection().getUri());
|
|
||||||
wallet.sync(); // blocking
|
|
||||||
connectionsService.doneDownload(); // TODO: using this to signify both daemon and wallet synced, refactor sync handling of both
|
|
||||||
wallet.save();
|
|
||||||
System.out.println("Loaded wallet balance: " + wallet.getBalance(0));
|
|
||||||
System.out.println("Loaded wallet unlocked balance: " + wallet.getUnlockedBalance(0));
|
|
||||||
|
|
||||||
// update wallet connections on change
|
// update wallet connections on change
|
||||||
connectionsService.addListener(newConnection -> {
|
connectionsService.addListener(newConnection -> {
|
||||||
setWalletDaemonConnections(newConnection);
|
setWalletDaemonConnections(newConnection);
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void tryInitMainWallet() {
|
||||||
|
MoneroWalletConfig walletConfig = new MoneroWalletConfig().setPath(MONERO_WALLET_NAME).setPassword(getWalletPassword());
|
||||||
|
if (MoneroUtils.walletExists(xmrWalletFile.getPath())) {
|
||||||
|
wallet = openWallet(walletConfig, rpcBindPort);
|
||||||
|
} else if (connectionsService.getConnection() != null && Boolean.TRUE.equals(connectionsService.getConnection().isConnected())) {
|
||||||
|
wallet = createWallet(walletConfig, rpcBindPort); // wallet requires connection to daemon to correctly set height
|
||||||
|
}
|
||||||
|
|
||||||
|
// wallet is not initialized until connected to a daemon
|
||||||
|
if (wallet != null) {
|
||||||
|
try {
|
||||||
|
wallet.sync(); // blocking
|
||||||
|
connectionsService.doneDownload(); // TODO: using this to signify both daemon and wallet synced, refactor sync handling of both
|
||||||
|
wallet.save();
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
System.out.println("Monero wallet path: " + wallet.getPath());
|
||||||
|
System.out.println("Monero wallet address: " + wallet.getPrimaryAddress());
|
||||||
|
System.out.println("Monero wallet uri: " + wallet.getRpcConnection().getUri());
|
||||||
|
System.out.println("Monero wallet height: " + wallet.getHeight());
|
||||||
|
System.out.println("Monero wallet balance: " + wallet.getBalance(0));
|
||||||
|
System.out.println("Monero wallet unlocked balance: " + wallet.getUnlockedBalance(0));
|
||||||
|
|
||||||
// notify on balance changes
|
// notify on balance changes
|
||||||
wallet.addListener(new MoneroWalletListener() {
|
wallet.addListener(new MoneroWalletListener() {
|
||||||
|
@ -315,6 +274,73 @@ public class XmrWalletService {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private MoneroWalletRpc createWallet(MoneroWalletConfig config, Integer port) {
|
||||||
|
|
||||||
|
// start monero-wallet-rpc instance
|
||||||
|
MoneroWalletRpc walletRpc = startWalletRpcInstance(port);
|
||||||
|
|
||||||
|
// must be connected to daemon
|
||||||
|
MoneroRpcConnection connection = connectionsService.getConnection();
|
||||||
|
if (connection == null || !Boolean.TRUE.equals(connection.isConnected())) throw new RuntimeException("Must be connected to daemon before creating wallet");
|
||||||
|
|
||||||
|
// create wallet
|
||||||
|
try {
|
||||||
|
walletRpc.createWallet(config);
|
||||||
|
walletRpc.startSyncing(MONERO_WALLET_SYNC_RATE);
|
||||||
|
return walletRpc;
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
MONERO_WALLET_RPC_MANAGER.stopInstance(walletRpc, false);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private MoneroWalletRpc openWallet(MoneroWalletConfig config, Integer port) {
|
||||||
|
|
||||||
|
// start monero-wallet-rpc instance
|
||||||
|
MoneroWalletRpc walletRpc = startWalletRpcInstance(port);
|
||||||
|
|
||||||
|
// open wallet
|
||||||
|
try {
|
||||||
|
walletRpc.openWallet(config);
|
||||||
|
walletRpc.startSyncing(MONERO_WALLET_SYNC_RATE);
|
||||||
|
return walletRpc;
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
MONERO_WALLET_RPC_MANAGER.stopInstance(walletRpc, false);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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");
|
||||||
|
|
||||||
|
// build command to start monero-wallet-rpc
|
||||||
|
List<String> cmd = new ArrayList<>(Arrays.asList( // modifiable list
|
||||||
|
MONERO_WALLET_RPC_PATH, "--" + MONERO_NETWORK_TYPE.toString().toLowerCase(), "--rpc-login",
|
||||||
|
MONERO_WALLET_RPC_USERNAME + ":" + getWalletPassword(), "--wallet-dir", walletDir.toString()));
|
||||||
|
MoneroRpcConnection connection = connectionsService.getConnection();
|
||||||
|
if (connection != null) {
|
||||||
|
cmd.add("--daemon-address");
|
||||||
|
cmd.add(connection.getUri());
|
||||||
|
if (connection.getUsername() != null) {
|
||||||
|
cmd.add("--daemon-login");
|
||||||
|
cmd.add(connection.getUsername() + ":" + connection.getPassword());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (port != null && port > 0) {
|
||||||
|
cmd.add("--rpc-bind-port");
|
||||||
|
cmd.add(Integer.toString(port));
|
||||||
|
}
|
||||||
|
|
||||||
|
// start monero-wallet-rpc instance and return connected client
|
||||||
|
return MONERO_WALLET_RPC_MANAGER.startInstance(cmd);
|
||||||
|
}
|
||||||
|
|
||||||
private void backupWallets() {
|
private void backupWallets() {
|
||||||
FileUtil.rollingBackup(walletDir, xmrWalletFile.getName(), 20);
|
FileUtil.rollingBackup(walletDir, xmrWalletFile.getName(), 20);
|
||||||
|
@ -324,6 +350,7 @@ public class XmrWalletService {
|
||||||
|
|
||||||
private void setWalletDaemonConnections(MoneroRpcConnection connection) {
|
private void setWalletDaemonConnections(MoneroRpcConnection connection) {
|
||||||
log.info("Setting wallet daemon connections: " + (connection == null ? null : connection.getUri()));
|
log.info("Setting wallet daemon connections: " + (connection == null ? null : connection.getUri()));
|
||||||
|
if (wallet == null) tryInitMainWallet();
|
||||||
if (wallet != null) wallet.setDaemonConnection(connection);
|
if (wallet != null) wallet.setDaemonConnection(connection);
|
||||||
for (MoneroWallet multisigWallet : multisigWallets.values()) multisigWallet.setDaemonConnection(connection);
|
for (MoneroWallet multisigWallet : multisigWallets.values()) multisigWallet.setDaemonConnection(connection);
|
||||||
}
|
}
|
||||||
|
@ -333,7 +360,7 @@ public class XmrWalletService {
|
||||||
Coin balance;
|
Coin balance;
|
||||||
if (balanceListener.getSubaddressIndex() != null && balanceListener.getSubaddressIndex() != 0) balance = getBalanceForSubaddress(balanceListener.getSubaddressIndex());
|
if (balanceListener.getSubaddressIndex() != null && balanceListener.getSubaddressIndex() != 0) balance = getBalanceForSubaddress(balanceListener.getSubaddressIndex());
|
||||||
else balance = getAvailableConfirmedBalance();
|
else balance = getAvailableConfirmedBalance();
|
||||||
UserThread.execute(new Runnable() {
|
UserThread.execute(new Runnable() { // TODO (woodser): don't execute on UserThread
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
balanceListener.onBalanceChanged(BigInteger.valueOf(balance.value));
|
balanceListener.onBalanceChanged(BigInteger.valueOf(balance.value));
|
||||||
|
@ -549,6 +576,7 @@ public class XmrWalletService {
|
||||||
return available.filter(addressEntry -> getBalanceForSubaddress(addressEntry.getSubaddressIndex()).isPositive());
|
return available.filter(addressEntry -> getBalanceForSubaddress(addressEntry.getSubaddressIndex()).isPositive());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO (woodser): update balance and other listening
|
||||||
public void addBalanceListener(XmrBalanceListener listener) {
|
public void addBalanceListener(XmrBalanceListener listener) {
|
||||||
balanceListeners.add(listener);
|
balanceListeners.add(listener);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue