Introduce LocalBitcoinNode and tests

This new class encapsulates all functionality related to detecting a
local Bitcoin node and reporting whether or not it was detected.
Previously this functionality was spread across the Config class
(formerly BisqEnvironment) with its mutable static
isLocalBitcoinNodeRunning property and the BisqSetup class with its
checkIfLocalHostNodeIsRunning method. All of this functionality now
lives within the LocalBitcoinNode class, an instance of which is wired
up via Guice and injected wherever necessary.

Note that the code for detecting whether the node is running has been
simplified, in that it is no longer wrapped in its own dedicated Thread.
There appears to be no performance benefit from doing so, and leaving it
in place would have made testing more difficult than necessary.

Several methods in BisqSetup have also been refactored to accept
callbacks indicating which step should be run next. This has the effect
of clarifying when the step2()-step5() methods will be called.
This commit is contained in:
Chris Beams 2020-01-08 20:07:30 +01:00
parent 4ea3290608
commit 876b91e1be
No known key found for this signature in database
GPG key ID: 3D214F8F5BC5ED73
13 changed files with 181 additions and 58 deletions

View file

@ -168,9 +168,6 @@ public class Config {
private final OptionParser parser = new OptionParser();
// legacy mutable property TODO: move to new LocalBitcoinNode class
private boolean localBitcoinNodeIsRunning = false;
public Config(String... args) {
this(tempAppName(), tempUserDataDir(), args);
}
@ -854,14 +851,6 @@ public class Config {
return logLevel;
}
public boolean isLocalBitcoinNodeIsRunning() {
return localBitcoinNodeIsRunning;
}
public void setLocalBitcoinNodeIsRunning(boolean value) {
this.localBitcoinNodeIsRunning = value;
}
public String getReferralId() {
return referralId;
}

View file

@ -26,6 +26,7 @@ import bisq.core.alert.PrivateNotificationManager;
import bisq.core.alert.PrivateNotificationPayload;
import bisq.core.btc.Balances;
import bisq.core.btc.model.AddressEntry;
import bisq.core.btc.nodes.LocalBitcoinNode;
import bisq.core.btc.setup.WalletsSetup;
import bisq.core.btc.wallet.BtcWalletService;
import bisq.core.btc.wallet.WalletsManager;
@ -90,8 +91,6 @@ import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import com.google.common.net.InetAddresses;
import org.fxmisc.easybind.EasyBind;
import org.fxmisc.easybind.monadic.MonadicBinding;
@ -106,9 +105,6 @@ import javafx.collections.SetChangeListener;
import org.spongycastle.crypto.params.KeyParameter;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.io.IOException;
import java.util.ArrayList;
@ -130,6 +126,7 @@ import javax.annotation.Nullable;
@Slf4j
@Singleton
public class BisqSetup {
public interface BisqSetupListener {
default void onInitP2pNetwork() {
log.info("onInitP2pNetwork");
@ -192,6 +189,8 @@ public class BisqSetup {
private final TorSetup torSetup;
private final TradeLimits tradeLimits;
private final CoinFormatter formatter;
private final LocalBitcoinNode localBitcoinNode;
@Setter
@Nullable
private Consumer<Runnable> displayTacHandler;
@ -281,8 +280,8 @@ public class BisqSetup {
AssetService assetService,
TorSetup torSetup,
TradeLimits tradeLimits,
@Named(FormattingUtils.BTC_FORMATTER_KEY) CoinFormatter formatter) {
@Named(FormattingUtils.BTC_FORMATTER_KEY) CoinFormatter formatter,
LocalBitcoinNode localBitcoinNode) {
this.p2PNetworkSetup = p2PNetworkSetup;
this.walletAppSetup = walletAppSetup;
@ -329,6 +328,7 @@ public class BisqSetup {
this.torSetup = torSetup;
this.tradeLimits = tradeLimits;
this.formatter = formatter;
this.localBitcoinNode = localBitcoinNode;
}
@ -348,18 +348,18 @@ public class BisqSetup {
}
private void step2() {
checkIfLocalHostNodeIsRunning();
detectLocalBitcoinNode(this::step3);
}
private void step3() {
torSetup.cleanupTorFiles();
readMapsFromResources();
readMapsFromResources(this::step4);
checkCryptoSetup();
checkForCorrectOSArchitecture();
}
private void step4() {
startP2pNetworkAndWallet();
startP2pNetworkAndWallet(this::step5);
}
private void step5() {
@ -482,33 +482,20 @@ public class BisqSetup {
}
}
private void checkIfLocalHostNodeIsRunning() {
private void detectLocalBitcoinNode(Runnable nextStep) {
BaseCurrencyNetwork baseCurrencyNetwork = config.getBaseCurrencyNetwork();
// For DAO testnet we ignore local btc node
if (baseCurrencyNetwork.isDaoRegTest() || baseCurrencyNetwork.isDaoTestNet() ||
config.isIgnoreLocalBtcNode()) {
step3();
} else {
new Thread(() -> {
try (Socket socket = new Socket()) {
socket.connect(new InetSocketAddress(InetAddresses.forString("127.0.0.1"),
baseCurrencyNetwork.getParameters().getPort()), 5000);
log.info("Localhost Bitcoin node detected.");
UserThread.execute(() -> {
config.setLocalBitcoinNodeIsRunning(true);
step3();
});
} catch (Throwable e) {
UserThread.execute(BisqSetup.this::step3);
}
}, "checkIfLocalHostNodeIsRunningThread").start();
if (config.isIgnoreLocalBtcNode() || baseCurrencyNetwork.isDaoRegTest() || baseCurrencyNetwork.isDaoTestNet()) {
nextStep.run();
return;
}
localBitcoinNode.detectAndRun(nextStep);
}
private void readMapsFromResources() {
private void readMapsFromResources(Runnable nextStep) {
SetupUtils.readFromResources(p2PService.getP2PDataStorage(), config).addListener((observable, oldValue, newValue) -> {
if (newValue)
step4();
nextStep.run();
});
}
@ -542,7 +529,7 @@ public class BisqSetup {
}, "checkCryptoThread").start();
}
private void startP2pNetworkAndWallet() {
private void startP2pNetworkAndWallet(Runnable nextStep) {
ChangeListener<Boolean> walletInitializedListener = (observable, oldValue, newValue) -> {
// TODO that seems to be called too often if Tor takes longer to start up...
if (newValue && !p2pNetworkReady.get() && displayTorNetworkSettingsHandler != null)
@ -572,7 +559,7 @@ public class BisqSetup {
// We only init wallet service here if not using Tor for bitcoinj.
// When using Tor, wallet init must be deferred until Tor is ready.
if (!preferences.getUseTorForBitcoinJ() || config.isLocalBitcoinNodeIsRunning()) {
if (!preferences.getUseTorForBitcoinJ() || localBitcoinNode.isDetected()) {
initWallet();
}
@ -588,7 +575,7 @@ public class BisqSetup {
walletInitialized.removeListener(walletInitializedListener);
if (displayTorNetworkSettingsHandler != null)
displayTorNetworkSettingsHandler.accept(false);
step5();
nextStep.run();
}
});
}
@ -875,7 +862,7 @@ public class BisqSetup {
}
private void maybeShowLocalhostRunningInfo() {
maybeTriggerDisplayHandler("bitcoinLocalhostNode", displayLocalhostHandler, config.isLocalBitcoinNodeIsRunning());
maybeTriggerDisplayHandler("bitcoinLocalhostNode", displayLocalhostHandler, localBitcoinNode.isDetected());
}
private void maybeShowAccountSigningStateInfo() {

View file

@ -47,6 +47,7 @@ import bisq.common.proto.persistable.PersistenceProtoResolver;
import java.io.File;
import static bisq.common.config.Config.*;
import static bisq.core.btc.nodes.LocalBitcoinNode.LOCAL_BITCOIN_NODE_PORT;
import static com.google.inject.name.Names.named;
public class CoreModule extends AppModule {
@ -77,6 +78,9 @@ public class CoreModule extends AppModule {
bindConstant().annotatedWith(named(USE_DEV_MODE)).to(config.isUseDevMode());
bindConstant().annotatedWith(named(REFERRAL_ID)).to(config.getReferralId());
bindConstant().annotatedWith(named(LOCAL_BITCOIN_NODE_PORT))
.to(config.getBaseCurrencyNetworkParameters().getPort());
// ordering is used for shut down sequence
install(new TradeModule(config));

View file

@ -50,6 +50,7 @@ import com.google.inject.Singleton;
import java.io.File;
import static bisq.common.config.Config.*;
import static bisq.core.btc.nodes.LocalBitcoinNode.LOCAL_BITCOIN_NODE_PORT;
import static com.google.inject.name.Names.named;
public class ModuleForAppWithP2p extends AppModule {
@ -81,6 +82,9 @@ public class ModuleForAppWithP2p extends AppModule {
bindConstant().annotatedWith(named(USE_DEV_MODE)).to(config.isUseDevMode());
bindConstant().annotatedWith(named(REFERRAL_ID)).to(config.getReferralId());
bindConstant().annotatedWith(named(LOCAL_BITCOIN_NODE_PORT))
.to(config.getBaseCurrencyNetworkParameters().getPort());
// ordering is used for shut down sequence
install(new TradeModule(config));
install(new EncryptionServiceModule(config));

View file

@ -0,0 +1,61 @@
package bisq.core.btc.nodes;
import javax.inject.Inject;
import javax.inject.Named;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.io.IOException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Detects whether a Bitcoin node is running on localhost.
* @see bisq.common.config.Config#isIgnoreLocalBtcNode()
*/
public class LocalBitcoinNode {
public static final String LOCAL_BITCOIN_NODE_PORT = "localBitcoinNodePort";
private static final Logger log = LoggerFactory.getLogger(LocalBitcoinNode.class);
private static final int CONNECTION_TIMEOUT = 5000;
private final int port;
private boolean detected = false;
@Inject
public LocalBitcoinNode(@Named(LOCAL_BITCOIN_NODE_PORT) int port) {
this.port = port;
}
/**
* Detect whether a Bitcoin node is running on localhost by attempting to connect
* to the node's port and run the given callback regardless of whether the connection
* was successful. If the connection is successful, subsequent calls to
* {@link #isDetected()} will return {@code true}.
* @param callback code to run after detecting whether the node is running
*/
public void detectAndRun(Runnable callback) {
try (Socket socket = new Socket()) {
socket.connect(new InetSocketAddress("127.0.0.1", port), CONNECTION_TIMEOUT);
log.info("Local Bitcoin node detected on port {}", port);
detected = true;
} catch (IOException ex) {
log.info("No local Bitcoin node detected on port {}.", port);
}
callback.run();
}
/**
* Returns whether or not a Bitcoin node was running on localhost at the time
* {@link #detectAndRun(Runnable)} was called. 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.
*/
public boolean isDetected() {
return detected;
}
}

View file

@ -17,6 +17,7 @@
package bisq.core.btc.setup;
import bisq.core.btc.nodes.LocalBitcoinNode;
import bisq.core.btc.nodes.ProxySocketFactory;
import bisq.core.btc.wallet.BisqRiskAnalysis;
@ -115,6 +116,7 @@ public class WalletConfig extends AbstractIdleService {
private final Socks5Proxy socks5Proxy;
private final BisqWalletFactory walletFactory;
private final Config config;
private final LocalBitcoinNode localBitcoinNode;
private final String userAgent;
private int numConnectionsForBtc;
@ -152,12 +154,14 @@ public class WalletConfig extends AbstractIdleService {
Socks5Proxy socks5Proxy,
File directory,
Config config,
LocalBitcoinNode localBitcoinNode,
String userAgent,
int numConnectionsForBtc,
@SuppressWarnings("SameParameterValue") String btcWalletFileName,
@SuppressWarnings("SameParameterValue") String bsqWalletFileName,
@SuppressWarnings("SameParameterValue") String spvChainFileName) {
this.config = config;
this.localBitcoinNode = localBitcoinNode;
this.userAgent = userAgent;
this.numConnectionsForBtc = numConnectionsForBtc;
this.context = new Context(params);
@ -239,7 +243,7 @@ public class WalletConfig extends AbstractIdleService {
// if local btc node is not synced with our dao testnet master node.
if (Config.baseCurrencyNetwork().isDaoRegTest() ||
Config.baseCurrencyNetwork().isDaoTestNet() ||
!config.isLocalBitcoinNodeIsRunning())
!localBitcoinNode.isDetected())
peerGroup.setUseLocalhostPeerWhenPossible(false);
return peerGroup;

View file

@ -18,6 +18,7 @@
package bisq.core.btc.setup;
import bisq.core.btc.exceptions.InvalidHostException;
import bisq.core.btc.nodes.LocalBitcoinNode;
import bisq.core.btc.exceptions.RejectedTxException;
import bisq.core.btc.model.AddressEntry;
import bisq.core.btc.model.AddressEntryList;
@ -118,6 +119,7 @@ public class WalletsSetup {
private final Preferences preferences;
private final Socks5ProxyProvider socks5ProxyProvider;
private final Config config;
private final LocalBitcoinNode localBitcoinNode;
private final BtcNodes btcNodes;
private final String btcWalletFileName;
private final int numConnectionsForBtc;
@ -145,6 +147,7 @@ public class WalletsSetup {
Preferences preferences,
Socks5ProxyProvider socks5ProxyProvider,
Config config,
LocalBitcoinNode localBitcoinNode,
BtcNodes btcNodes,
@Named(Config.USER_AGENT) String userAgent,
@Named(Config.WALLET_DIR) File walletDir,
@ -156,6 +159,7 @@ public class WalletsSetup {
this.preferences = preferences;
this.socks5ProxyProvider = socks5ProxyProvider;
this.config = config;
this.localBitcoinNode = localBitcoinNode;
this.btcNodes = btcNodes;
this.numConnectionsForBtc = numConnectionsForBtc;
this.useAllProvidedNodes = useAllProvidedNodes;
@ -196,6 +200,7 @@ public class WalletsSetup {
socks5Proxy,
walletDir,
config,
localBitcoinNode,
userAgent,
numConnectionsForBtc,
btcWalletFileName,
@ -273,7 +278,7 @@ public class WalletsSetup {
return;
}
}
} else if (config.isLocalBitcoinNodeIsRunning()) {
} else if (localBitcoinNode.isDetected()) {
walletConfig.setMinBroadcastConnections(1);
walletConfig.setPeerNodesForLocalHost();
} else {

View file

@ -17,6 +17,7 @@
package bisq.core.user;
import bisq.core.btc.nodes.LocalBitcoinNode;
import bisq.core.btc.nodes.BtcNodes;
import bisq.core.btc.wallet.Restrictions;
import bisq.core.locale.Country;
@ -133,6 +134,7 @@ public final class Preferences implements PersistedDataHost, BridgeAddressProvid
private final Storage<PreferencesPayload> storage;
private final Config config;
private final LocalBitcoinNode localBitcoinNode;
private final String btcNodesFromOptions, referralIdFromOptions,
rpcUserFromOptions, rpcPwFromOptions;
private final int blockNotifyPortFromOptions;
@ -150,6 +152,7 @@ public final class Preferences implements PersistedDataHost, BridgeAddressProvid
@Inject
public Preferences(Storage<PreferencesPayload> storage,
Config config,
LocalBitcoinNode localBitcoinNode,
@Named(Config.BTC_NODES) String btcNodesFromOptions,
@Named(Config.REFERRAL_ID) String referralId,
@Named(Config.FULL_DAO_NODE) boolean fullDaoNode,
@ -159,6 +162,7 @@ public final class Preferences implements PersistedDataHost, BridgeAddressProvid
this.storage = storage;
this.config = config;
this.localBitcoinNode = localBitcoinNode;
this.btcNodesFromOptions = btcNodesFromOptions;
this.referralIdFromOptions = referralId;
this.fullDaoNodeFromOptions = fullDaoNode;
@ -736,7 +740,7 @@ public final class Preferences implements PersistedDataHost, BridgeAddressProvid
// unless the useTorForBtc parameter is explicitly provided.
// On testnet there are very few Bitcoin tor nodes and we don't provide tor nodes.
if ((!Config.baseCurrencyNetwork().isMainnet()
|| config.isLocalBitcoinNodeIsRunning())
|| localBitcoinNode.isDetected())
&& !config.isUseTorForBtcOptionSetExplicitly())
return false;
else

View file

@ -0,0 +1,55 @@
package bisq.core.btc.nodes;
import java.net.ServerSocket;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.util.concurrent.atomic.AtomicBoolean;
import org.junit.Before;
import org.junit.Test;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
public class LocalBitcoinNodeTests {
private AtomicBoolean called = new AtomicBoolean(false);
private Runnable callback = () -> called.set(true);
private int port;
private LocalBitcoinNode localBitcoinNode;
@Before
public void setUp() throws IOException {
// Find an available port
try (ServerSocket socket = new ServerSocket(0)) {
port = socket.getLocalPort();
}
localBitcoinNode = new LocalBitcoinNode(port);
}
@Test
public void whenLocalBitcoinNodeIsDetected_thenCallbackGetsRun_andIsDetectedReturnsTrue() {
// Listen on the port, indicating that the local bitcoin node is running
new Thread(() -> {
try (ServerSocket socket = new ServerSocket(port)){
socket.accept();
} catch (IOException ex) {
throw new UncheckedIOException(ex);
}
}).start();
localBitcoinNode.detectAndRun(callback);
assertTrue(called.get());
assertTrue(localBitcoinNode.isDetected());
}
@Test
public void whenLocalBitcoinNodeIsNotDetected_thenCallbackGetsRun_andIsDetectedReturnsFalse() {
// Leave port unbound, indicating that no local Bitcoin node is running
localBitcoinNode.detectAndRun(callback);
assertTrue(called.get());
assertFalse(localBitcoinNode.isDetected());
}
}

View file

@ -17,6 +17,7 @@
package bisq.core.user;
import bisq.core.btc.nodes.LocalBitcoinNode;
import bisq.core.locale.CountryUtil;
import bisq.core.locale.CryptoCurrency;
import bisq.core.locale.CurrencyUtil;
@ -58,8 +59,10 @@ public class PreferencesTest {
Res.setBaseCurrencyName("Bitcoin");
storage = mock(Storage.class);
Config config = new Config();
LocalBitcoinNode localBitcoinNode = new LocalBitcoinNode(config.getBaseCurrencyNetworkParameters().getPort());
preferences = new Preferences(
storage, new Config(), null, null, Config.DEFAULT_FULL_DAO_NODE,
storage, config, localBitcoinNode, null, null, Config.DEFAULT_FULL_DAO_NODE,
null, null, Config.UNSPECIFIED_PORT);
}

View file

@ -41,6 +41,7 @@ import bisq.core.account.sign.SignedWitnessService;
import bisq.core.account.witness.AccountAgeWitnessService;
import bisq.core.alert.PrivateNotificationManager;
import bisq.core.app.BisqSetup;
import bisq.core.btc.nodes.LocalBitcoinNode;
import bisq.core.btc.setup.WalletsSetup;
import bisq.core.btc.wallet.BtcWalletService;
import bisq.common.config.Config;
@ -118,6 +119,7 @@ public class MainViewModel implements ViewModel, BisqSetup.BisqSetupListener {
@Getter
private final PriceFeedService priceFeedService;
private final Config config;
private final LocalBitcoinNode localBitcoinNode;
private final AccountAgeWitnessService accountAgeWitnessService;
@Getter
private final TorNetworkSettingsWindow torNetworkSettingsWindow;
@ -158,6 +160,7 @@ public class MainViewModel implements ViewModel, BisqSetup.BisqSetupListener {
FeeService feeService,
PriceFeedService priceFeedService,
Config config,
LocalBitcoinNode localBitcoinNode,
AccountAgeWitnessService accountAgeWitnessService,
TorNetworkSettingsWindow torNetworkSettingsWindow,
CorruptedDatabaseFilesHandler corruptedDatabaseFilesHandler) {
@ -179,6 +182,7 @@ public class MainViewModel implements ViewModel, BisqSetup.BisqSetupListener {
this.tacWindow = tacWindow;
this.priceFeedService = priceFeedService;
this.config = config;
this.localBitcoinNode = localBitcoinNode;
this.accountAgeWitnessService = accountAgeWitnessService;
this.torNetworkSettingsWindow = torNetworkSettingsWindow;
this.corruptedDatabaseFilesHandler = corruptedDatabaseFilesHandler;
@ -436,7 +440,7 @@ public class MainViewModel implements ViewModel, BisqSetup.BisqSetupListener {
checkNumberOfBtcPeersTimer = UserThread.runAfter(() -> {
// check again numPeers
if (walletsSetup.numPeersProperty().get() == 0) {
if (config.isLocalBitcoinNodeIsRunning())
if (localBitcoinNode.isDetected())
getWalletServiceErrorMsg().set(Res.get("mainView.networkWarning.localhostBitcoinLost", Res.getBaseCurrencyName().toLowerCase()));
else
getWalletServiceErrorMsg().set(Res.get("mainView.networkWarning.allConnectionsLost", Res.getBaseCurrencyName().toLowerCase()));

View file

@ -29,6 +29,7 @@ import bisq.desktop.main.overlays.windows.TorNetworkSettingsWindow;
import bisq.desktop.util.GUIUtil;
import bisq.desktop.util.validation.RegexValidator;
import bisq.core.btc.nodes.LocalBitcoinNode;
import bisq.core.btc.nodes.BtcNodes;
import bisq.core.btc.setup.WalletsSetup;
import bisq.core.filter.Filter;
@ -42,7 +43,6 @@ import bisq.network.p2p.network.Statistic;
import bisq.common.ClockWatcher;
import bisq.common.UserThread;
import bisq.common.config.Config;
import javax.inject.Inject;
@ -108,7 +108,7 @@ public class NetworkSettingsView extends ActivatableView<GridPane, Void> {
private final Preferences preferences;
private final BtcNodes btcNodes;
private final FilterManager filterManager;
private final Config config;
private final LocalBitcoinNode localBitcoinNode;
private final TorNetworkSettingsWindow torNetworkSettingsWindow;
private final ClockWatcher clockWatcher;
private final WalletsSetup walletsSetup;
@ -137,7 +137,7 @@ public class NetworkSettingsView extends ActivatableView<GridPane, Void> {
Preferences preferences,
BtcNodes btcNodes,
FilterManager filterManager,
Config config,
LocalBitcoinNode localBitcoinNode,
TorNetworkSettingsWindow torNetworkSettingsWindow,
ClockWatcher clockWatcher) {
super();
@ -146,7 +146,7 @@ public class NetworkSettingsView extends ActivatableView<GridPane, Void> {
this.preferences = preferences;
this.btcNodes = btcNodes;
this.filterManager = filterManager;
this.config = config;
this.localBitcoinNode = localBitcoinNode;
this.torNetworkSettingsWindow = torNetworkSettingsWindow;
this.clockWatcher = clockWatcher;
}
@ -165,7 +165,7 @@ public class NetworkSettingsView extends ActivatableView<GridPane, Void> {
bitcoinPeerSubVersionColumn.setGraphic(new AutoTooltipLabel(Res.get("settings.net.subVersionColumn")));
bitcoinPeerHeightColumn.setGraphic(new AutoTooltipLabel(Res.get("settings.net.heightColumn")));
localhostBtcNodeInfoLabel.setText(Res.get("settings.net.localhostBtcNodeInfo"));
if (!config.isLocalBitcoinNodeIsRunning()) {
if (!localBitcoinNode.isDetected()) {
localhostBtcNodeInfoLabel.setVisible(false);
}
useProvidedNodesRadio.setText(Res.get("settings.net.useProvidedNodesRadio"));
@ -380,7 +380,7 @@ public class NetworkSettingsView extends ActivatableView<GridPane, Void> {
}
private void onBitcoinPeersToggleSelected(boolean calledFromUser) {
boolean bitcoinLocalhostNodeRunning = config.isLocalBitcoinNodeIsRunning();
boolean bitcoinLocalhostNodeRunning = localBitcoinNode.isDetected();
useTorForBtcJCheckBox.setDisable(bitcoinLocalhostNodeRunning);
bitcoinNodesLabel.setDisable(bitcoinLocalhostNodeRunning);
btcNodesLabel.setDisable(bitcoinLocalhostNodeRunning);
@ -460,7 +460,7 @@ public class NetworkSettingsView extends ActivatableView<GridPane, Void> {
private void applyPreventPublicBtcNetwork() {
final boolean preventPublicBtcNetwork = isPreventPublicBtcNetwork();
usePublicNodesRadio.setDisable(config.isLocalBitcoinNodeIsRunning() || preventPublicBtcNetwork);
usePublicNodesRadio.setDisable(localBitcoinNode.isDetected() || preventPublicBtcNetwork);
if (preventPublicBtcNetwork && selectedBitcoinNodesOption == BtcNodes.BitcoinNodesOption.PUBLIC) {
selectedBitcoinNodesOption = BtcNodes.BitcoinNodesOption.PROVIDED;
preferences.setBitcoinNodesOptionOrdinal(selectedBitcoinNodesOption.ordinal());

View file

@ -17,6 +17,7 @@
package bisq.desktop.maker;
import bisq.core.btc.nodes.LocalBitcoinNode;
import bisq.core.user.Preferences;
import bisq.common.config.Config;
@ -33,12 +34,14 @@ public class PreferenceMakers {
public static final Property<bisq.core.user.Preferences, Storage> storage = new Property<>();
public static final Property<Preferences, Config> config = new Property<>();
public static final Property<Preferences, LocalBitcoinNode> localBitcoinNode = new Property<>();
public static final Property<Preferences, String> useTorFlagFromOptions = new Property<>();
public static final Property<Preferences, String> referralID = new Property<>();
public static final Instantiator<Preferences> Preferences = lookup -> new Preferences(
lookup.valueOf(storage, new SameValueDonor<Storage>(null)),
lookup.valueOf(config, new SameValueDonor<Config>(null)),
lookup.valueOf(localBitcoinNode, new SameValueDonor<LocalBitcoinNode>(null)),
lookup.valueOf(useTorFlagFromOptions, new SameValueDonor<String>(null)),
lookup.valueOf(referralID, new SameValueDonor<String>(null)),
Config.DEFAULT_FULL_DAO_NODE, null, null, Config.UNSPECIFIED_PORT);