replace LocalBitcoinNode with LocalMoneroNode

This commit is contained in:
woodser 2023-08-17 11:50:51 -04:00
parent d50ab5782b
commit 740374c9db
28 changed files with 92 additions and 169 deletions

View file

@ -87,7 +87,7 @@ public class CoreApi {
private final TradeStatisticsManager tradeStatisticsManager;
private final CoreNotificationService notificationService;
private final CoreMoneroConnectionsService coreMoneroConnectionsService;
private final CoreMoneroNodeService coreMoneroNodeService;
private final LocalMoneroNode coreMoneroNodeService;
@Inject
public CoreApi(Config config,
@ -104,7 +104,7 @@ public class CoreApi {
TradeStatisticsManager tradeStatisticsManager,
CoreNotificationService notificationService,
CoreMoneroConnectionsService coreMoneroConnectionsService,
CoreMoneroNodeService coreMoneroNodeService) {
LocalMoneroNode coreMoneroNodeService) {
this.config = config;
this.appStartupState = appStartupState;
this.coreAccountService = coreAccountService;
@ -236,7 +236,7 @@ public class CoreApi {
///////////////////////////////////////////////////////////////////////////////////////////
public boolean isMoneroNodeOnline() {
return coreMoneroNodeService.isOnline();
return coreMoneroNodeService.isDetected();
}
public MoneroNodeSettings getMoneroNodeSettings() {

View file

@ -57,7 +57,7 @@ public final class CoreMoneroConnectionsService {
private final Preferences preferences;
private final CoreAccountService accountService;
private final XmrNodes xmrNodes;
private final CoreMoneroNodeService nodeService;
private final LocalMoneroNode nodeService;
private final MoneroConnectionManager connectionManager;
private final EncryptedConnectionList connectionList;
private final ObjectProperty<List<MoneroPeer>> peers = new SimpleObjectProperty<>();
@ -82,7 +82,7 @@ public final class CoreMoneroConnectionsService {
WalletsSetup walletsSetup,
CoreAccountService accountService,
XmrNodes xmrNodes,
CoreMoneroNodeService nodeService,
LocalMoneroNode nodeService,
MoneroConnectionManager connectionManager,
EncryptedConnectionList connectionList,
Socks5ProxyProvider socks5ProxyProvider) {
@ -374,7 +374,7 @@ public final class CoreMoneroConnectionsService {
if (!isInitialized) {
// register local node listener
nodeService.addListener(new MoneroNodeServiceListener() {
nodeService.addListener(new LocalMoneroNodeListener() {
@Override
public void onNodeStarted(MoneroDaemonRpc daemon) {
log.info(getClass() + ".onNodeStarted() called");
@ -481,7 +481,7 @@ public final class CoreMoneroConnectionsService {
if (HavenoUtils.havenoSetup == null) return;
// start local node if offline and used as last connection
if (connectionManager.getConnection() != null && nodeService.equalsUri(connectionManager.getConnection().getUri()) && !nodeService.isOnline()) {
if (connectionManager.getConnection() != null && nodeService.equalsUri(connectionManager.getConnection().getUri()) && !nodeService.isDetected()) {
try {
log.info("Starting local node");
nodeService.startMoneroNode();

View file

@ -25,7 +25,6 @@ import haveno.core.xmr.MoneroNodeSettings;
import lombok.extern.slf4j.Slf4j;
import monero.common.MoneroUtils;
import monero.daemon.MoneroDaemonRpc;
import javax.inject.Inject;
import javax.inject.Singleton;
import java.io.File;
@ -38,15 +37,16 @@ import java.util.List;
*/
@Slf4j
@Singleton
public class CoreMoneroNodeService {
public class LocalMoneroNode {
public static final String MONEROD_DIR = Config.baseCurrencyNetwork() == BaseCurrencyNetwork.XMR_LOCAL ? System.getProperty("user.dir") + File.separator + ".localnet" : Config.appDataDir().getAbsolutePath();
public static final String MONEROD_NAME = Utilities.isWindows() ? "monerod.exe" : "monerod";
public static final String MONEROD_PATH = MONEROD_DIR + File.separator + MONEROD_NAME;
private static final String MONEROD_DATADIR = Config.baseCurrencyNetwork() == BaseCurrencyNetwork.XMR_LOCAL ? MONEROD_DIR + File.separator + Config.baseCurrencyNetwork().toString().toLowerCase() + File.separator + "node1" : null; // use default directory unless local
private final Config config;
private final Preferences preferences;
private final List<MoneroNodeServiceListener> listeners = new ArrayList<>();
private final List<LocalMoneroNodeListener> listeners = new ArrayList<>();
// required arguments
private static final List<String> MONEROD_ARGS = new ArrayList<String>();
@ -68,16 +68,34 @@ public class CoreMoneroNodeService {
}
@Inject
public CoreMoneroNodeService(Preferences preferences) {
public LocalMoneroNode(Config config, Preferences preferences) {
this.config = config;
this.preferences = preferences;
this.daemon = new MoneroDaemonRpc("http://" + HavenoUtils.LOOPBACK_HOST + ":" + rpcPort);
}
public void addListener(MoneroNodeServiceListener listener) {
/**
* Returns whether Haveno should use a local Monero node, meaning that a node was
* detected and conditions under which it should be ignored have not been met. If
* the local node should be ignored, a call to this method will not trigger an
* unnecessary detection attempt.
*/
public boolean shouldBeUsed() {
return !shouldBeIgnored() && isDetected();
}
/**
* Returns whether Haveno should ignore a local Monero node even if it is usable.
*/
public boolean shouldBeIgnored() {
return config.ignoreLocalXmrNode;
}
public void addListener(LocalMoneroNodeListener listener) {
listeners.add(listener);
}
public boolean removeListener(MoneroNodeServiceListener listener) {
public boolean removeListener(LocalMoneroNodeListener listener) {
return listeners.remove(listener);
}
@ -97,9 +115,9 @@ public class CoreMoneroNodeService {
}
/**
* Check if local Monero node is online.
* Check if local Monero node is detected.
*/
public boolean isOnline() {
public boolean isDetected() {
checkConnection();
return daemon.getRpcConnection().isOnline();
}
@ -129,7 +147,7 @@ public class CoreMoneroNodeService {
* Persist the settings to preferences if the node started successfully.
*/
public void startMoneroNode(MoneroNodeSettings settings) throws IOException {
if (isOnline()) throw new IllegalStateException("Local Monero node already online");
if (isDetected()) throw new IllegalStateException("Local Monero node already online");
log.info("Starting local Monero node: " + settings);
@ -161,7 +179,7 @@ public class CoreMoneroNodeService {
* Does not remove the last MoneroNodeSettings.
*/
public void stopMoneroNode() {
if (!isOnline()) throw new IllegalStateException("Local Monero node is not running");
if (!isDetected()) throw new IllegalStateException("Local Monero node is not running");
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();
for (var listener : listeners) listener.onNodeStopped();

View file

@ -18,7 +18,7 @@ package haveno.core.api;
import monero.daemon.MoneroDaemonRpc;
public class MoneroNodeServiceListener {
public class LocalMoneroNodeListener {
public void onNodeStarted(MoneroDaemonRpc daemon) {}
public void onNodeStopped() {}
}

View file

@ -33,7 +33,7 @@ import haveno.core.alert.Alert;
import haveno.core.alert.AlertManager;
import haveno.core.alert.PrivateNotificationManager;
import haveno.core.alert.PrivateNotificationPayload;
import haveno.core.api.CoreMoneroNodeService;
import haveno.core.api.LocalMoneroNode;
import haveno.core.locale.Res;
import haveno.core.offer.OpenOfferManager;
import haveno.core.payment.AmazonGiftCardAccount;
@ -52,7 +52,6 @@ import haveno.core.user.User;
import haveno.core.util.FormattingUtils;
import haveno.core.util.coin.CoinFormatter;
import haveno.core.xmr.model.AddressEntry;
import haveno.core.xmr.nodes.LocalBitcoinNode;
import haveno.core.xmr.setup.WalletsSetup;
import haveno.core.xmr.wallet.BtcWalletService;
import haveno.core.xmr.wallet.WalletsManager;
@ -121,7 +120,7 @@ public class HavenoSetup {
private final AccountAgeWitnessService accountAgeWitnessService;
private final TorSetup torSetup;
private final CoinFormatter formatter;
private final LocalBitcoinNode localBitcoinNode;
private final LocalMoneroNode localMoneroNode;
private final AppStartupState appStartupState;
private final MediationManager mediationManager;
private final RefundManager refundManager;
@ -215,7 +214,7 @@ public class HavenoSetup {
AccountAgeWitnessService accountAgeWitnessService,
TorSetup torSetup,
@Named(FormattingUtils.BTC_FORMATTER_KEY) CoinFormatter formatter,
LocalBitcoinNode localBitcoinNode,
LocalMoneroNode localMoneroNode,
AppStartupState appStartupState,
Socks5ProxyProvider socks5ProxyProvider,
MediationManager mediationManager,
@ -240,7 +239,7 @@ public class HavenoSetup {
this.accountAgeWitnessService = accountAgeWitnessService;
this.torSetup = torSetup;
this.formatter = formatter;
this.localBitcoinNode = localBitcoinNode;
this.localMoneroNode = localMoneroNode;
this.appStartupState = appStartupState;
this.mediationManager = mediationManager;
this.refundManager = refundManager;
@ -339,12 +338,12 @@ public class HavenoSetup {
private void maybeInstallDependencies() {
try {
File monerodFile = new File(CoreMoneroNodeService.MONEROD_PATH);
String monerodResourcePath = "bin/" + CoreMoneroNodeService.MONEROD_NAME;
File monerodFile = new File(LocalMoneroNode.MONEROD_PATH);
String monerodResourcePath = "bin/" + LocalMoneroNode.MONEROD_NAME;
if (!monerodFile.exists() || !FileUtil.resourceEqualToFile(monerodResourcePath, monerodFile)) {
log.info("Installing monerod");
monerodFile.getParentFile().mkdirs();
FileUtil.resourceToFile("bin/" + CoreMoneroNodeService.MONEROD_NAME, monerodFile);
FileUtil.resourceToFile("bin/" + LocalMoneroNode.MONEROD_NAME, monerodFile);
monerodFile.setExecutable(true);
}
@ -621,7 +620,7 @@ public class HavenoSetup {
}
private void maybeShowLocalhostRunningInfo() {
maybeTriggerDisplayHandler("bitcoinLocalhostNode", displayLocalhostHandler, localBitcoinNode.shouldBeUsed());
maybeTriggerDisplayHandler("moneroLocalhostNode", displayLocalhostHandler, localMoneroNode.shouldBeUsed());
}
private void maybeShowAccountSigningStateInfo() {

View file

@ -33,7 +33,6 @@ import haveno.core.payment.PaymentAccount;
import haveno.core.payment.PaymentAccountUtil;
import haveno.core.xmr.MoneroNodeSettings;
import haveno.core.xmr.nodes.XmrNodes;
import haveno.core.xmr.nodes.LocalBitcoinNode;
import haveno.core.xmr.wallet.Restrictions;
import haveno.network.p2p.network.BridgeAddressProvider;
import javafx.beans.property.BooleanProperty;
@ -153,7 +152,6 @@ public final class Preferences implements PersistedDataHost, BridgeAddressProvid
private final PersistenceManager<PreferencesPayload> persistenceManager;
private final Config config;
private final LocalBitcoinNode localBitcoinNode;
private final String xmrNodesFromOptions;
@Getter
private final BooleanProperty useStandbyModeProperty = new SimpleBooleanProperty(prefPayload.isUseStandbyMode());
@ -165,12 +163,10 @@ public final class Preferences implements PersistedDataHost, BridgeAddressProvid
@Inject
public Preferences(PersistenceManager<PreferencesPayload> persistenceManager,
Config config,
LocalBitcoinNode localBitcoinNode,
@Named(Config.XMR_NODES) String xmrNodesFromOptions) {
this.persistenceManager = persistenceManager;
this.config = config;
this.localBitcoinNode = localBitcoinNode;
this.xmrNodesFromOptions = xmrNodesFromOptions;
useAnimationsProperty.addListener((ov) -> {

View file

@ -1,85 +0,0 @@
package haveno.core.xmr.nodes;
import haveno.common.config.BaseCurrencyNetwork;
import haveno.common.config.Config;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.inject.Inject;
import javax.inject.Singleton;
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
/**
* Detects whether a Bitcoin node is running on localhost and contains logic for when to
* ignore it. The query methods lazily trigger the needed checks and cache the results.
* @see haveno.common.config.Config#ignoreLocalXmrNode
*/
@Singleton
public class LocalBitcoinNode {
private static final Logger log = LoggerFactory.getLogger(LocalBitcoinNode.class);
private static final int CONNECTION_TIMEOUT = 5000;
private final Config config;
private final int port;
private Boolean detected;
@Inject
public LocalBitcoinNode(Config config) {
this.config = config;
this.port = config.networkParameters.getPort();
}
/**
* Returns whether Haveno should use a local Bitcoin node, meaning that a node was
* detected and conditions under which it should be ignored have not been met. If
* the local node should be ignored, a call to this method will not trigger an
* unnecessary detection attempt.
*/
public boolean shouldBeUsed() {
return !shouldBeIgnored() && isDetected();
}
/**
* Returns whether Haveno should ignore a local Bitcoin node even if it is usable.
*/
public boolean shouldBeIgnored() {
BaseCurrencyNetwork baseCurrencyNetwork = config.baseCurrencyNetwork;
return config.ignoreLocalXmrNode;
}
/**
* Returns whether a local Bitcoin node was detected. The check is triggered in case
* it has not been performed. No further monitoring is performed, so if the node
* goes up or down in the meantime, this method will continue to return its original
* value. See {@code MainViewModel#setupBtcNumPeersWatcher} to understand how
* disconnection and reconnection of the local Bitcoin node is actually handled.
*/
private boolean isDetected() {
if (detected == null) {
detected = detect(port);
}
return detected;
}
/**
* Detect whether a Bitcoin node is running on localhost by attempting to connect
* to the node's port.
*/
private static boolean detect(int port) {
try (Socket socket = new Socket()) {
var address = new InetSocketAddress(InetAddress.getLoopbackAddress(), port);
socket.connect(address, CONNECTION_TIMEOUT);
log.info("Local Bitcoin node detected on port {}", port);
return true;
} catch (IOException ex) {
log.info("No local Bitcoin node detected on port {}.", port);
return false;
}
}
}

View file

@ -22,7 +22,7 @@ import com.google.common.util.concurrent.AbstractIdleService;
import com.runjva.sourceforge.jsocks.protocol.Socks5Proxy;
import haveno.common.config.Config;
import haveno.common.file.FileUtil;
import haveno.core.xmr.nodes.LocalBitcoinNode;
import haveno.core.api.LocalMoneroNode;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import lombok.Getter;
@ -103,7 +103,7 @@ public class WalletConfig extends AbstractIdleService {
protected volatile Context context;
protected Config config;
protected LocalBitcoinNode localBitcoinNode;
protected LocalMoneroNode localMoneroNode;
protected Socks5Proxy socks5Proxy;
protected int numConnectionsForBtc;
@Getter
@ -143,9 +143,9 @@ public class WalletConfig extends AbstractIdleService {
return this;
}
public WalletConfig setLocalBitcoinNode(LocalBitcoinNode localBitcoinNode) {
public WalletConfig setLocalMoneroNodeService(LocalMoneroNode localMoneroNode) {
checkState(state() == State.NEW, "Cannot call after startup");
this.localBitcoinNode = localBitcoinNode;
this.localMoneroNode = localMoneroNode;
return this;
}

View file

@ -29,6 +29,7 @@ import haveno.common.config.Config;
import haveno.common.file.FileUtil;
import haveno.common.handlers.ExceptionHandler;
import haveno.common.handlers.ResultHandler;
import haveno.core.api.LocalMoneroNode;
import haveno.core.user.Preferences;
import haveno.core.xmr.exceptions.InvalidHostException;
import haveno.core.xmr.model.AddressEntry;
@ -38,7 +39,6 @@ import haveno.core.xmr.nodes.XmrNodes;
import haveno.core.xmr.nodes.XmrNodes.XmrNode;
import haveno.core.xmr.nodes.XmrNodesRepository;
import haveno.core.xmr.nodes.XmrNodesSetupPreferences;
import haveno.core.xmr.nodes.LocalBitcoinNode;
import haveno.network.Socks5MultiDiscovery;
import haveno.network.Socks5ProxyProvider;
import javafx.beans.property.BooleanProperty;
@ -100,7 +100,7 @@ public class WalletsSetup {
private final Preferences preferences;
private final Socks5ProxyProvider socks5ProxyProvider;
private final Config config;
private final LocalBitcoinNode localBitcoinNode;
private final LocalMoneroNode localMoneroNode;
private final XmrNodes xmrNodes;
private final int numConnectionsForBtc;
private final String userAgent;
@ -126,7 +126,7 @@ public class WalletsSetup {
Preferences preferences,
Socks5ProxyProvider socks5ProxyProvider,
Config config,
LocalBitcoinNode localBitcoinNode,
LocalMoneroNode localMoneroNode,
XmrNodes xmrNodes,
@Named(Config.USER_AGENT) String userAgent,
@Named(Config.WALLET_DIR) File walletDir,
@ -138,7 +138,7 @@ public class WalletsSetup {
this.preferences = preferences;
this.socks5ProxyProvider = socks5ProxyProvider;
this.config = config;
this.localBitcoinNode = localBitcoinNode;
this.localMoneroNode = localMoneroNode;
this.xmrNodes = xmrNodes;
this.numConnectionsForBtc = numConnectionsForBtc;
this.useAllProvidedNodes = useAllProvidedNodes;
@ -195,7 +195,7 @@ public class WalletsSetup {
};
walletConfig.setSocks5Proxy(socks5Proxy);
walletConfig.setConfig(config);
walletConfig.setLocalBitcoinNode(localBitcoinNode); // TODO: adapt to xmr or remove
walletConfig.setLocalMoneroNodeService(localMoneroNode); // TODO: adapt to xmr or remove
walletConfig.setUserAgent(userAgent, Version.VERSION);
walletConfig.setNumConnectionsForBtc(numConnectionsForBtc);
@ -230,7 +230,7 @@ public class WalletsSetup {
return;
}
}
} else if (localBitcoinNode.shouldBeUsed()) {
} else if (localMoneroNode.shouldBeUsed()) {
walletConfig.setMinBroadcastConnections(1);
walletConfig.connectToLocalHost();
} else {