mirror of
https://github.com/haveno-dex/haveno.git
synced 2025-07-30 02:08:58 -04:00
Add btc network selector to preferences
This commit is contained in:
parent
c1e0524090
commit
844a6dd66c
17 changed files with 248 additions and 82 deletions
|
@ -22,7 +22,6 @@ import io.bitsquare.p2p.BootstrapNodes;
|
||||||
import io.bitsquare.p2p.Node;
|
import io.bitsquare.p2p.Node;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Random;
|
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import net.tomp2p.dht.PeerBuilderDHT;
|
import net.tomp2p.dht.PeerBuilderDHT;
|
||||||
|
@ -45,6 +44,9 @@ public class BootstrapNode {
|
||||||
|
|
||||||
private static final String VERSION = "0.1.3";
|
private static final String VERSION = "0.1.3";
|
||||||
|
|
||||||
|
public static final String P2P_ID = "node.p2pId";
|
||||||
|
public static int DEFAULT_P2P_ID = 1; // 0 | 1 | 2 for mainnet/testnet/regtest
|
||||||
|
|
||||||
private static Peer peer = null;
|
private static Peer peer = null;
|
||||||
|
|
||||||
private final Environment env;
|
private final Environment env;
|
||||||
|
@ -56,12 +58,13 @@ public class BootstrapNode {
|
||||||
|
|
||||||
|
|
||||||
public void start() {
|
public void start() {
|
||||||
int port = env.getProperty(Node.PORT_KEY, Integer.class, BootstrapNodes.PORT);
|
int p2pId = env.getProperty(P2P_ID, Integer.class, DEFAULT_P2P_ID);
|
||||||
String name = env.getProperty(Node.NAME_KEY, BootstrapNodes.DEFAULT_NODE_NAME);
|
int port = env.getProperty(Node.PORT_KEY, Integer.class, BootstrapNodes.BASE_PORT + p2pId);
|
||||||
|
String name = env.getRequiredProperty(Node.NAME_KEY);
|
||||||
Logging.setup(name + "_" + port);
|
Logging.setup(name + "_" + port);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Number160 peerId = Number160.createHash(new Random().nextInt());
|
Number160 peerId = Number160.createHash(name);
|
||||||
/*
|
/*
|
||||||
DefaultEventExecutorGroup eventExecutorGroup = new DefaultEventExecutorGroup(50);
|
DefaultEventExecutorGroup eventExecutorGroup = new DefaultEventExecutorGroup(50);
|
||||||
ChannelClientConfiguration clientConf = PeerBuilder.createDefaultChannelClientConfiguration();
|
ChannelClientConfiguration clientConf = PeerBuilder.createDefaultChannelClientConfiguration();
|
||||||
|
@ -73,6 +76,7 @@ public class BootstrapNode {
|
||||||
|
|
||||||
peer = new PeerBuilder(peerId)
|
peer = new PeerBuilder(peerId)
|
||||||
.ports(port)
|
.ports(port)
|
||||||
|
.p2pId(p2pId)
|
||||||
/* .channelClientConfiguration(clientConf)
|
/* .channelClientConfiguration(clientConf)
|
||||||
.channelServerConfiguration(serverConf)*/
|
.channelServerConfiguration(serverConf)*/
|
||||||
.start();
|
.start();
|
||||||
|
@ -87,7 +91,7 @@ public class BootstrapNode {
|
||||||
|
|
||||||
if (!name.equals(BootstrapNodes.LOCALHOST.getName())) {
|
if (!name.equals(BootstrapNodes.LOCALHOST.getName())) {
|
||||||
Collection<PeerAddress> bootstrapNodes = BootstrapNodes.getAllBootstrapNodes().stream().filter(e -> !e.getName().equals(name))
|
Collection<PeerAddress> bootstrapNodes = BootstrapNodes.getAllBootstrapNodes().stream().filter(e -> !e.getName().equals(name))
|
||||||
.map(e -> e.toPeerAddress()).collect(Collectors.toList());
|
.map(e -> e.toPeerAddressWithPort(port)).collect(Collectors.toList());
|
||||||
|
|
||||||
log.info("Bootstrapping to " + bootstrapNodes.size() + " bootstrapNode(s)");
|
log.info("Bootstrapping to " + bootstrapNodes.size() + " bootstrapNode(s)");
|
||||||
log.info("Bootstrapping bootstrapNodes " + bootstrapNodes);
|
log.info("Bootstrapping bootstrapNodes " + bootstrapNodes);
|
||||||
|
|
|
@ -32,9 +32,13 @@ public class BootstrapNodeMain extends BitsquareExecutable {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void customizeOptionParsing(OptionParser parser) {
|
protected void customizeOptionParsing(OptionParser parser) {
|
||||||
parser.accepts(Node.NAME_KEY, description("Name of this node", BootstrapNodes.DEFAULT_NODE_NAME))
|
parser.accepts(Node.NAME_KEY, description("Name of this node", null))
|
||||||
.withRequiredArg();
|
.withRequiredArg()
|
||||||
parser.accepts(Node.PORT_KEY, description("Port to listen on", BootstrapNodes.PORT))
|
.isRequired();
|
||||||
|
parser.accepts(Node.PORT_KEY, description("Port to listen on", BootstrapNodes.BASE_PORT))
|
||||||
|
.withRequiredArg()
|
||||||
|
.ofType(int.class);
|
||||||
|
parser.accepts(BootstrapNode.P2P_ID, description("P2P Network ID [0 | 1 | 2 for mainnet/testnet/regtest]", BootstrapNode.DEFAULT_P2P_ID))
|
||||||
.withRequiredArg()
|
.withRequiredArg()
|
||||||
.ofType(int.class);
|
.ofType(int.class);
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,6 @@
|
||||||
package io.bitsquare.app;
|
package io.bitsquare.app;
|
||||||
|
|
||||||
import io.bitsquare.BitsquareException;
|
import io.bitsquare.BitsquareException;
|
||||||
import io.bitsquare.btc.BitcoinNetwork;
|
|
||||||
import io.bitsquare.btc.UserAgent;
|
import io.bitsquare.btc.UserAgent;
|
||||||
import io.bitsquare.btc.WalletService;
|
import io.bitsquare.btc.WalletService;
|
||||||
import io.bitsquare.crypto.KeyStorage;
|
import io.bitsquare.crypto.KeyStorage;
|
||||||
|
@ -88,12 +87,8 @@ public class BitsquareEnvironment extends StandardEnvironment {
|
||||||
(String) commandLineProperties.getProperty(APP_DATA_DIR_KEY) :
|
(String) commandLineProperties.getProperty(APP_DATA_DIR_KEY) :
|
||||||
appDataDir(userDataDir, appName);
|
appDataDir(userDataDir, appName);
|
||||||
|
|
||||||
String bitcoinNetwork = commandLineProperties.containsProperty(BitcoinNetwork.KEY) ?
|
|
||||||
(String) commandLineProperties.getProperty(BitcoinNetwork.KEY) :
|
|
||||||
BitcoinNetwork.DEFAULT.toString();
|
|
||||||
|
|
||||||
this.bootstrapNodePort = commandLineProperties.containsProperty(TomP2PModule.BOOTSTRAP_NODE_PORT_KEY) ?
|
this.bootstrapNodePort = commandLineProperties.containsProperty(TomP2PModule.BOOTSTRAP_NODE_PORT_KEY) ?
|
||||||
(String) commandLineProperties.getProperty(TomP2PModule.BOOTSTRAP_NODE_PORT_KEY) : String.valueOf(BootstrapNodes.PORT);
|
(String) commandLineProperties.getProperty(TomP2PModule.BOOTSTRAP_NODE_PORT_KEY) : String.valueOf(BootstrapNodes.BASE_PORT);
|
||||||
|
|
||||||
MutablePropertySources propertySources = this.getPropertySources();
|
MutablePropertySources propertySources = this.getPropertySources();
|
||||||
propertySources.addFirst(commandLineProperties);
|
propertySources.addFirst(commandLineProperties);
|
||||||
|
|
|
@ -40,7 +40,6 @@ public class BitcoinModule extends BitsquareModule {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void configure() {
|
protected void configure() {
|
||||||
bind(BitcoinNetwork.class).toInstance(env.getProperty(BitcoinNetwork.KEY, BitcoinNetwork.class, BitcoinNetwork.DEFAULT));
|
|
||||||
bind(RegTestHost.class).toInstance(env.getProperty(RegTestHost.KEY, RegTestHost.class, RegTestHost.DEFAULT));
|
bind(RegTestHost.class).toInstance(env.getProperty(RegTestHost.KEY, RegTestHost.class, RegTestHost.DEFAULT));
|
||||||
bind(FeePolicy.class).in(Singleton.class);
|
bind(FeePolicy.class).in(Singleton.class);
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,9 @@ import org.bitcoinj.params.MainNetParams;
|
||||||
import org.bitcoinj.params.RegTestParams;
|
import org.bitcoinj.params.RegTestParams;
|
||||||
import org.bitcoinj.params.TestNet3Params;
|
import org.bitcoinj.params.TestNet3Params;
|
||||||
|
|
||||||
public enum BitcoinNetwork {
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
public enum BitcoinNetwork implements Serializable {
|
||||||
|
|
||||||
MAINNET(MainNetParams.get()),
|
MAINNET(MainNetParams.get()),
|
||||||
TESTNET(TestNet3Params.get()),
|
TESTNET(TestNet3Params.get()),
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
package io.bitsquare.btc;
|
package io.bitsquare.btc;
|
||||||
|
|
||||||
import io.bitsquare.BitsquareException;
|
import io.bitsquare.BitsquareException;
|
||||||
|
import io.bitsquare.user.Preferences;
|
||||||
|
|
||||||
import org.bitcoinj.core.Address;
|
import org.bitcoinj.core.Address;
|
||||||
import org.bitcoinj.core.AddressFormatException;
|
import org.bitcoinj.core.AddressFormatException;
|
||||||
|
@ -41,8 +42,8 @@ public class FeePolicy {
|
||||||
private final String takeOfferFeeAddress;
|
private final String takeOfferFeeAddress;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public FeePolicy(BitcoinNetwork bitcoinNetwork) {
|
public FeePolicy(Preferences preferences) {
|
||||||
this.bitcoinNetwork = bitcoinNetwork;
|
this.bitcoinNetwork = preferences.getBitcoinNetwork();
|
||||||
|
|
||||||
switch (bitcoinNetwork) {
|
switch (bitcoinNetwork) {
|
||||||
case TESTNET:
|
case TESTNET:
|
||||||
|
|
|
@ -20,6 +20,7 @@ package io.bitsquare.btc;
|
||||||
import io.bitsquare.btc.exceptions.SigningException;
|
import io.bitsquare.btc.exceptions.SigningException;
|
||||||
import io.bitsquare.btc.exceptions.TransactionVerificationException;
|
import io.bitsquare.btc.exceptions.TransactionVerificationException;
|
||||||
import io.bitsquare.btc.exceptions.WalletException;
|
import io.bitsquare.btc.exceptions.WalletException;
|
||||||
|
import io.bitsquare.user.Preferences;
|
||||||
|
|
||||||
import org.bitcoinj.core.Address;
|
import org.bitcoinj.core.Address;
|
||||||
import org.bitcoinj.core.AddressFormatException;
|
import org.bitcoinj.core.AddressFormatException;
|
||||||
|
@ -91,8 +92,8 @@ public class TradeWalletService {
|
||||||
private final FeePolicy feePolicy;
|
private final FeePolicy feePolicy;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public TradeWalletService(BitcoinNetwork bitcoinNetwork, FeePolicy feePolicy) {
|
public TradeWalletService(Preferences preferences, FeePolicy feePolicy) {
|
||||||
this.params = bitcoinNetwork.getParameters();
|
this.params = preferences.getBitcoinNetwork().getParameters();
|
||||||
this.feePolicy = feePolicy;
|
this.feePolicy = feePolicy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,7 @@ import io.bitsquare.btc.listeners.AddressConfidenceListener;
|
||||||
import io.bitsquare.btc.listeners.BalanceListener;
|
import io.bitsquare.btc.listeners.BalanceListener;
|
||||||
import io.bitsquare.btc.listeners.TxConfidenceListener;
|
import io.bitsquare.btc.listeners.TxConfidenceListener;
|
||||||
import io.bitsquare.crypto.CryptoService;
|
import io.bitsquare.crypto.CryptoService;
|
||||||
|
import io.bitsquare.user.Preferences;
|
||||||
|
|
||||||
import org.bitcoinj.core.AbstractWalletEventListener;
|
import org.bitcoinj.core.AbstractWalletEventListener;
|
||||||
import org.bitcoinj.core.Address;
|
import org.bitcoinj.core.Address;
|
||||||
|
@ -127,15 +128,15 @@ public class WalletService {
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public WalletService(BitcoinNetwork bitcoinNetwork, RegTestHost regTestHost, CryptoService cryptoService,
|
public WalletService(RegTestHost regTestHost, CryptoService cryptoService,
|
||||||
TradeWalletService tradeWalletService, AddressEntryList addressEntryList, UserAgent userAgent,
|
TradeWalletService tradeWalletService, AddressEntryList addressEntryList, UserAgent userAgent,
|
||||||
@Named(DIR_KEY) File walletDir, @Named(PREFIX_KEY) String walletPrefix) {
|
@Named(DIR_KEY) File walletDir, @Named(PREFIX_KEY) String walletPrefix, Preferences preferences) {
|
||||||
this.regTestHost = regTestHost;
|
this.regTestHost = regTestHost;
|
||||||
this.tradeWalletService = tradeWalletService;
|
this.tradeWalletService = tradeWalletService;
|
||||||
this.addressEntryList = addressEntryList;
|
this.addressEntryList = addressEntryList;
|
||||||
this.params = bitcoinNetwork.getParameters();
|
this.params = preferences.getBitcoinNetwork().getParameters();
|
||||||
this.cryptoService = cryptoService;
|
this.cryptoService = cryptoService;
|
||||||
this.walletDir = walletDir;
|
this.walletDir = new File(walletDir, preferences.getBitcoinNetwork().toString().toLowerCase());
|
||||||
this.walletPrefix = walletPrefix;
|
this.walletPrefix = walletPrefix;
|
||||||
this.userAgent = userAgent;
|
this.userAgent = userAgent;
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,20 +27,19 @@ import org.slf4j.LoggerFactory;
|
||||||
public class BootstrapNodes {
|
public class BootstrapNodes {
|
||||||
private static final Logger log = LoggerFactory.getLogger(BootstrapNodes.class);
|
private static final Logger log = LoggerFactory.getLogger(BootstrapNodes.class);
|
||||||
|
|
||||||
public static final int PORT = 7366;
|
public static final int BASE_PORT = 7366; // port will be evaluated from btc network 7366 for mainnet, 7367 for testnet and 7368 for regtest
|
||||||
public static final String DEFAULT_NODE_NAME = "default";
|
|
||||||
|
|
||||||
private static List<Node> bootstrapNodes = Arrays.asList(
|
private static List<Node> bootstrapNodes = Arrays.asList(
|
||||||
Node.at(DEFAULT_NODE_NAME, "188.226.179.109", PORT),
|
//Node.at("digitalocean1.bitsquare.io", "188.226.179.109", BASE_PORT),
|
||||||
Node.at(DEFAULT_NODE_NAME, "52.24.144.42", PORT),
|
Node.at("aws1.bitsquare.io", "52.24.144.42", BASE_PORT),
|
||||||
Node.at(DEFAULT_NODE_NAME, "52.11.125.194", PORT)
|
Node.at("aws2.bitsquare.io", "52.11.125.194", BASE_PORT)
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A locally-running BootstrapNode instance.
|
* A locally-running BootstrapNode instance.
|
||||||
* Typically used only for testing. Not included in results from {@link #getAllBootstrapNodes()}.
|
* Typically used only for testing. Not included in results from {@link #getAllBootstrapNodes()}.
|
||||||
*/
|
*/
|
||||||
public static Node LOCALHOST = Node.at("localhost", "127.0.0.1", PORT);
|
public static Node LOCALHOST = Node.at("localhost", "127.0.0.1", BASE_PORT);
|
||||||
|
|
||||||
private static Node selectedNode = bootstrapNodes.get(new Random().nextInt(bootstrapNodes.size()));
|
private static Node selectedNode = bootstrapNodes.get(new Random().nextInt(bootstrapNodes.size()));
|
||||||
|
|
||||||
|
|
|
@ -94,12 +94,12 @@ public final class Node {
|
||||||
return port;
|
return port;
|
||||||
}
|
}
|
||||||
|
|
||||||
public PeerAddress toPeerAddress() {
|
public PeerAddress toPeerAddressWithPort(int port) {
|
||||||
try {
|
try {
|
||||||
return new PeerAddress(Number160.createHash(getName()),
|
return new PeerAddress(Number160.createHash(getName()),
|
||||||
InetAddress.getByName(getIp()),
|
InetAddress.getByName(getIp()),
|
||||||
getPort(),
|
port,
|
||||||
getPort());
|
port);
|
||||||
} catch (UnknownHostException e) {
|
} catch (UnknownHostException e) {
|
||||||
log.error("toPeerAddress failed: " + e.getMessage());
|
log.error("toPeerAddress failed: " + e.getMessage());
|
||||||
return null;
|
return null;
|
||||||
|
|
|
@ -19,6 +19,7 @@ package io.bitsquare.p2p.tomp2p;
|
||||||
|
|
||||||
import io.bitsquare.p2p.BootstrapNodes;
|
import io.bitsquare.p2p.BootstrapNodes;
|
||||||
import io.bitsquare.p2p.Node;
|
import io.bitsquare.p2p.Node;
|
||||||
|
import io.bitsquare.user.Preferences;
|
||||||
|
|
||||||
import com.google.common.util.concurrent.SettableFuture;
|
import com.google.common.util.concurrent.SettableFuture;
|
||||||
|
|
||||||
|
@ -114,17 +115,17 @@ public class BootstrappedPeerBuilder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private KeyPair keyPair;
|
|
||||||
private final int port;
|
private final int port;
|
||||||
private final boolean useManualPortForwarding;
|
private final boolean useManualPortForwarding;
|
||||||
private Node bootstrapNode;
|
|
||||||
private final String networkInterface;
|
private final String networkInterface;
|
||||||
|
private final Preferences preferences;
|
||||||
|
|
||||||
private final SettableFuture<PeerDHT> settableFuture = SettableFuture.create();
|
private final SettableFuture<PeerDHT> settableFuture = SettableFuture.create();
|
||||||
|
|
||||||
private final ObjectProperty<State> state = new SimpleObjectProperty<>(State.UNDEFINED);
|
private final ObjectProperty<State> state = new SimpleObjectProperty<>(State.UNDEFINED);
|
||||||
private final ObjectProperty<ConnectionType> connectionType = new SimpleObjectProperty<>(ConnectionType.UNDEFINED);
|
private final ObjectProperty<ConnectionType> connectionType = new SimpleObjectProperty<>(ConnectionType.UNDEFINED);
|
||||||
|
|
||||||
|
private Node bootstrapNode;
|
||||||
|
private KeyPair keyPair;
|
||||||
private Peer peer;
|
private Peer peer;
|
||||||
private PeerDHT peerDHT;
|
private PeerDHT peerDHT;
|
||||||
private boolean retriedOtherBootstrapNode;
|
private boolean retriedOtherBootstrapNode;
|
||||||
|
@ -139,13 +140,13 @@ public class BootstrappedPeerBuilder {
|
||||||
public BootstrappedPeerBuilder(@Named(Node.PORT_KEY) int port,
|
public BootstrappedPeerBuilder(@Named(Node.PORT_KEY) int port,
|
||||||
@Named(USE_MANUAL_PORT_FORWARDING_KEY) boolean useManualPortForwarding,
|
@Named(USE_MANUAL_PORT_FORWARDING_KEY) boolean useManualPortForwarding,
|
||||||
@Named(BOOTSTRAP_NODE_KEY) Node bootstrapNode,
|
@Named(BOOTSTRAP_NODE_KEY) Node bootstrapNode,
|
||||||
@Named(NETWORK_INTERFACE_KEY) String networkInterface) {
|
@Named(NETWORK_INTERFACE_KEY) String networkInterface,
|
||||||
|
Preferences preferences) {
|
||||||
this.port = port;
|
this.port = port;
|
||||||
this.useManualPortForwarding = useManualPortForwarding;
|
this.useManualPortForwarding = useManualPortForwarding;
|
||||||
this.bootstrapNode = bootstrapNode;
|
this.bootstrapNode = bootstrapNode;
|
||||||
this.networkInterface = networkInterface;
|
this.networkInterface = networkInterface;
|
||||||
|
this.preferences = preferences;
|
||||||
log.debug("Bootstrap to {}", bootstrapNode.toString());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -168,6 +169,10 @@ public class BootstrappedPeerBuilder {
|
||||||
|
|
||||||
public SettableFuture<PeerDHT> start(int networkId) {
|
public SettableFuture<PeerDHT> start(int networkId) {
|
||||||
try {
|
try {
|
||||||
|
// port is evaluated from btc network. 7366 for mainnet, 7367 for testnet and 7368 for regtest
|
||||||
|
bootstrapNode = Node.at(bootstrapNode.getName(), bootstrapNode.getIp(), bootstrapNode.getPort() + networkId);
|
||||||
|
log.debug("Bootstrap to {}", bootstrapNode.toString());
|
||||||
|
|
||||||
DefaultEventExecutorGroup eventExecutorGroup = new DefaultEventExecutorGroup(20);
|
DefaultEventExecutorGroup eventExecutorGroup = new DefaultEventExecutorGroup(20);
|
||||||
ChannelClientConfiguration clientConf = PeerBuilder.createDefaultChannelClientConfiguration();
|
ChannelClientConfiguration clientConf = PeerBuilder.createDefaultChannelClientConfiguration();
|
||||||
clientConf.pipelineFilter(new PeerBuilder.EventExecutorGroupFilter(eventExecutorGroup));
|
clientConf.pipelineFilter(new PeerBuilder.EventExecutorGroupFilter(eventExecutorGroup));
|
||||||
|
@ -219,7 +224,9 @@ public class BootstrappedPeerBuilder {
|
||||||
// log.debug("Peer updated: peerAddress=" + peerAddress + ", peerStatistics=" + peerStatistics);
|
// log.debug("Peer updated: peerAddress=" + peerAddress + ", peerStatistics=" + peerStatistics);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
if (preferences.getUseUPnP())
|
||||||
|
discoverExternalAddressUsingUPnP();
|
||||||
|
else
|
||||||
discoverExternalAddress();
|
discoverExternalAddress();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
handleError(State.PEER_CREATION_FAILED, "Cannot create a peer with port: " +
|
handleError(State.PEER_CREATION_FAILED, "Cannot create a peer with port: " +
|
||||||
|
@ -247,10 +254,11 @@ public class BootstrappedPeerBuilder {
|
||||||
// 4. If the port forwarding failed we can try as last resort to open a permanent TCP connection to the
|
// 4. If the port forwarding failed we can try as last resort to open a permanent TCP connection to the
|
||||||
// bootstrap node and use that peer as relay
|
// bootstrap node and use that peer as relay
|
||||||
|
|
||||||
private void discoverExternalAddress() {
|
private void discoverExternalAddressUsingUPnP() {
|
||||||
FutureDiscover futureDiscover = peer.discover().peerAddress(getBootstrapAddress()).start();
|
FutureDiscover futureDiscover = peer.discover().peerAddress(getBootstrapAddress()).start();
|
||||||
setState(State.DISCOVERY_STARTED);
|
setState(State.DISCOVERY_STARTED);
|
||||||
PeerNAT peerNAT = new PeerBuilderNAT(peer).start();
|
PeerNAT peerNAT = new PeerBuilderNAT(peer).start();
|
||||||
|
|
||||||
FutureNAT futureNAT = peerNAT.startSetupPortforwarding(futureDiscover);
|
FutureNAT futureNAT = peerNAT.startSetupPortforwarding(futureDiscover);
|
||||||
FutureRelayNAT futureRelayNAT = peerNAT.startRelay(new TCPRelayClientConfig(), futureDiscover, futureNAT);
|
FutureRelayNAT futureRelayNAT = peerNAT.startRelay(new TCPRelayClientConfig(), futureDiscover, futureNAT);
|
||||||
|
|
||||||
|
@ -312,6 +320,62 @@ public class BootstrappedPeerBuilder {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void discoverExternalAddress() {
|
||||||
|
FutureDiscover futureDiscover = peer.discover().peerAddress(getBootstrapAddress()).start();
|
||||||
|
setState(State.DISCOVERY_STARTED);
|
||||||
|
PeerNAT peerNAT = new PeerBuilderNAT(peer).start();
|
||||||
|
|
||||||
|
FutureRelayNAT futureRelayNAT = peerNAT.startRelay(new TCPRelayClientConfig(), futureDiscover);
|
||||||
|
|
||||||
|
futureRelayNAT.addListener(new BaseFutureListener<BaseFuture>() {
|
||||||
|
@Override
|
||||||
|
public void operationComplete(BaseFuture futureRelayNAT) throws Exception {
|
||||||
|
if (futureDiscover.isSuccess()) {
|
||||||
|
if (useManualPortForwarding) {
|
||||||
|
setState(State.DISCOVERY_MANUAL_PORT_FORWARDING_SUCCEEDED,
|
||||||
|
"NAT traversal successful with manual port forwarding.");
|
||||||
|
setConnectionType(ConnectionType.MANUAL_PORT_FORWARDING);
|
||||||
|
bootstrap();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
setState(State.DISCOVERY_DIRECT_SUCCEEDED, "Visible to the network. No NAT traversal needed.");
|
||||||
|
setConnectionType(ConnectionType.DIRECT);
|
||||||
|
bootstrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (futureRelayNAT.isSuccess()) {
|
||||||
|
// relay mode succeeded
|
||||||
|
setState(State.RELAY_SUCCEEDED, "Using relay mode.");
|
||||||
|
setConnectionType(ConnectionType.RELAY);
|
||||||
|
bootstrap();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (!retriedOtherBootstrapNode && BootstrapNodes.getAllBootstrapNodes().size() > 1) {
|
||||||
|
log.warn("Bootstrap failed with bootstrapNode: " + bootstrapNode + ". We try again with another node.");
|
||||||
|
retriedOtherBootstrapNode = true;
|
||||||
|
Optional<Node> optional = BootstrapNodes.getAllBootstrapNodes().stream().filter(e -> !e.equals(bootstrapNode)).findAny();
|
||||||
|
if (optional.isPresent()) {
|
||||||
|
bootstrapNode = optional.get();
|
||||||
|
executor.execute(() -> discoverExternalAddress());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// All attempts failed. Give up...
|
||||||
|
handleError(State.RELAY_FAILED, "NAT traversal using relay mode failed " +
|
||||||
|
futureRelayNAT.failedReason());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void exceptionCaught(Throwable t) throws Exception {
|
||||||
|
handleError(State.RELAY_FAILED, "Exception at bootstrap: " + t.getMessage());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private void bootstrap() {
|
private void bootstrap() {
|
||||||
log.trace("start bootstrap");
|
log.trace("start bootstrap");
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
package io.bitsquare.user;
|
package io.bitsquare.user;
|
||||||
|
|
||||||
import io.bitsquare.app.Version;
|
import io.bitsquare.app.Version;
|
||||||
|
import io.bitsquare.btc.BitcoinNetwork;
|
||||||
import io.bitsquare.storage.Storage;
|
import io.bitsquare.storage.Storage;
|
||||||
|
|
||||||
import org.bitcoinj.utils.MonetaryFormat;
|
import org.bitcoinj.utils.MonetaryFormat;
|
||||||
|
@ -37,6 +38,8 @@ import javafx.beans.property.StringProperty;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import org.springframework.core.env.Environment;
|
||||||
|
|
||||||
public class Preferences implements Serializable {
|
public class Preferences implements Serializable {
|
||||||
// That object is saved to disc. We need to take care of changes to not break deserialization.
|
// That object is saved to disc. We need to take care of changes to not break deserialization.
|
||||||
private static final long serialVersionUID = Version.LOCAL_DB_VERSION;
|
private static final long serialVersionUID = Version.LOCAL_DB_VERSION;
|
||||||
|
@ -45,7 +48,6 @@ public class Preferences implements Serializable {
|
||||||
|
|
||||||
// Deactivate mBit for now as most screens are not supporting it yet
|
// Deactivate mBit for now as most screens are not supporting it yet
|
||||||
transient private static final List<String> BTC_DENOMINATIONS = Arrays.asList(MonetaryFormat.CODE_BTC/*, MonetaryFormat.CODE_MBTC*/);
|
transient private static final List<String> BTC_DENOMINATIONS = Arrays.asList(MonetaryFormat.CODE_BTC/*, MonetaryFormat.CODE_MBTC*/);
|
||||||
|
|
||||||
public static List<String> getBtcDenominations() {
|
public static List<String> getBtcDenominations() {
|
||||||
return BTC_DENOMINATIONS;
|
return BTC_DENOMINATIONS;
|
||||||
}
|
}
|
||||||
|
@ -54,21 +56,25 @@ public class Preferences implements Serializable {
|
||||||
|
|
||||||
// Persisted fields
|
// Persisted fields
|
||||||
private String btcDenomination = MonetaryFormat.CODE_BTC;
|
private String btcDenomination = MonetaryFormat.CODE_BTC;
|
||||||
|
|
||||||
private boolean useAnimations = true;
|
private boolean useAnimations = true;
|
||||||
private boolean useEffects = true;
|
private boolean useEffects = true;
|
||||||
private boolean displaySecurityDepositInfo = true;
|
private boolean displaySecurityDepositInfo = true;
|
||||||
|
private boolean useUPnP = true;
|
||||||
|
private BitcoinNetwork bitcoinNetwork;
|
||||||
|
|
||||||
// Observable wrappers
|
// Observable wrappers
|
||||||
transient private final StringProperty btcDenominationProperty = new SimpleStringProperty(btcDenomination);
|
transient private final StringProperty btcDenominationProperty = new SimpleStringProperty(btcDenomination);
|
||||||
transient private final BooleanProperty useAnimationsProperty = new SimpleBooleanProperty(useAnimations);
|
transient private final BooleanProperty useAnimationsProperty = new SimpleBooleanProperty(useAnimations);
|
||||||
transient private final BooleanProperty useEffectsProperty = new SimpleBooleanProperty(useEffects);
|
transient private final BooleanProperty useEffectsProperty = new SimpleBooleanProperty(useEffects);
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// Constructor
|
// Constructor
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public Preferences(Storage<Preferences> storage) {
|
public Preferences(Storage<Preferences> storage, Environment environment) {
|
||||||
this.storage = storage;
|
this.storage = storage;
|
||||||
|
|
||||||
Preferences persisted = storage.initAndGetPersisted(this);
|
Preferences persisted = storage.initAndGetPersisted(this);
|
||||||
|
@ -76,8 +82,13 @@ public class Preferences implements Serializable {
|
||||||
setBtcDenomination(persisted.btcDenomination);
|
setBtcDenomination(persisted.btcDenomination);
|
||||||
setUseAnimations(persisted.useAnimations);
|
setUseAnimations(persisted.useAnimations);
|
||||||
setUseEffects(persisted.useEffects);
|
setUseEffects(persisted.useEffects);
|
||||||
|
setUseUPnP(persisted.useUPnP);
|
||||||
|
setBitcoinNetwork(persisted.bitcoinNetwork);
|
||||||
displaySecurityDepositInfo = persisted.getDisplaySecurityDepositInfo();
|
displaySecurityDepositInfo = persisted.getDisplaySecurityDepositInfo();
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
setBitcoinNetwork(environment.getProperty(BitcoinNetwork.KEY, BitcoinNetwork.class, BitcoinNetwork.DEFAULT));
|
||||||
|
}
|
||||||
|
|
||||||
// Use that to guarantee update of the serializable field and to make a storage update in case of a change
|
// Use that to guarantee update of the serializable field and to make a storage update in case of a change
|
||||||
btcDenominationProperty.addListener((ov) -> {
|
btcDenominationProperty.addListener((ov) -> {
|
||||||
|
@ -116,6 +127,16 @@ public class Preferences implements Serializable {
|
||||||
storage.queueUpForSave();
|
storage.queueUpForSave();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setUseUPnP(boolean useUPnP) {
|
||||||
|
this.useUPnP = useUPnP;
|
||||||
|
storage.queueUpForSave();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBitcoinNetwork(BitcoinNetwork bitcoinNetwork) {
|
||||||
|
this.bitcoinNetwork = bitcoinNetwork;
|
||||||
|
storage.queueUpForSave();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// Getter
|
// Getter
|
||||||
|
@ -149,5 +170,11 @@ public class Preferences implements Serializable {
|
||||||
return useEffectsProperty;
|
return useEffectsProperty;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean getUseUPnP() {
|
||||||
|
return useUPnP;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BitcoinNetwork getBitcoinNetwork() {
|
||||||
|
return bitcoinNetwork;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,6 +69,8 @@ public class BitsquareApp extends Application {
|
||||||
private List<String> corruptedDatabaseFiles = new ArrayList<>();
|
private List<String> corruptedDatabaseFiles = new ArrayList<>();
|
||||||
private MainView mainView;
|
private MainView mainView;
|
||||||
|
|
||||||
|
public static Runnable shutDownHandler;
|
||||||
|
|
||||||
public static void setEnvironment(Environment env) {
|
public static void setEnvironment(Environment env) {
|
||||||
BitsquareApp.env = env;
|
BitsquareApp.env = env;
|
||||||
}
|
}
|
||||||
|
@ -77,6 +79,8 @@ public class BitsquareApp extends Application {
|
||||||
public void start(Stage primaryStage) throws IOException {
|
public void start(Stage primaryStage) throws IOException {
|
||||||
this.primaryStage = primaryStage;
|
this.primaryStage = primaryStage;
|
||||||
|
|
||||||
|
shutDownHandler = this::stop;
|
||||||
|
|
||||||
// setup UncaughtExceptionHandler
|
// setup UncaughtExceptionHandler
|
||||||
Thread.UncaughtExceptionHandler handler = (thread, throwable) -> {
|
Thread.UncaughtExceptionHandler handler = (thread, throwable) -> {
|
||||||
// Might come from another thread
|
// Might come from another thread
|
||||||
|
|
|
@ -20,7 +20,6 @@ package io.bitsquare.gui.main;
|
||||||
import io.bitsquare.app.UpdateProcess;
|
import io.bitsquare.app.UpdateProcess;
|
||||||
import io.bitsquare.app.Version;
|
import io.bitsquare.app.Version;
|
||||||
import io.bitsquare.arbitration.ArbitrationRepository;
|
import io.bitsquare.arbitration.ArbitrationRepository;
|
||||||
import io.bitsquare.btc.BitcoinNetwork;
|
|
||||||
import io.bitsquare.btc.WalletService;
|
import io.bitsquare.btc.WalletService;
|
||||||
import io.bitsquare.crypto.KeyRing;
|
import io.bitsquare.crypto.KeyRing;
|
||||||
import io.bitsquare.fiat.FiatAccount;
|
import io.bitsquare.fiat.FiatAccount;
|
||||||
|
@ -33,6 +32,7 @@ import io.bitsquare.p2p.tomp2p.BootstrappedPeerBuilder;
|
||||||
import io.bitsquare.trade.Trade;
|
import io.bitsquare.trade.Trade;
|
||||||
import io.bitsquare.trade.TradeManager;
|
import io.bitsquare.trade.TradeManager;
|
||||||
import io.bitsquare.trade.offer.OpenOfferManager;
|
import io.bitsquare.trade.offer.OpenOfferManager;
|
||||||
|
import io.bitsquare.user.Preferences;
|
||||||
import io.bitsquare.user.User;
|
import io.bitsquare.user.User;
|
||||||
import io.bitsquare.util.Utilities;
|
import io.bitsquare.util.Utilities;
|
||||||
|
|
||||||
|
@ -117,7 +117,7 @@ class MainViewModel implements ViewModel {
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public MainViewModel(User user, KeyRing keyRing, WalletService walletService, ArbitrationRepository arbitrationRepository, ClientNode clientNode,
|
public MainViewModel(User user, KeyRing keyRing, WalletService walletService, ArbitrationRepository arbitrationRepository, ClientNode clientNode,
|
||||||
TradeManager tradeManager, OpenOfferManager openOfferManager, BitcoinNetwork bitcoinNetwork, UpdateProcess updateProcess,
|
TradeManager tradeManager, OpenOfferManager openOfferManager, Preferences preferences, UpdateProcess updateProcess,
|
||||||
BSFormatter formatter) {
|
BSFormatter formatter) {
|
||||||
this.user = user;
|
this.user = user;
|
||||||
this.keyRing = keyRing;
|
this.keyRing = keyRing;
|
||||||
|
@ -129,8 +129,8 @@ class MainViewModel implements ViewModel {
|
||||||
this.updateProcess = updateProcess;
|
this.updateProcess = updateProcess;
|
||||||
this.formatter = formatter;
|
this.formatter = formatter;
|
||||||
|
|
||||||
bitcoinNetworkAsString = formatter.formatBitcoinNetwork(bitcoinNetwork);
|
bitcoinNetworkAsString = formatter.formatBitcoinNetwork(preferences.getBitcoinNetwork());
|
||||||
networkId = bitcoinNetwork.ordinal();
|
networkId = preferences.getBitcoinNetwork().ordinal();
|
||||||
|
|
||||||
updateProcess.state.addListener((observableValue, oldValue, newValue) -> applyUpdateState(newValue));
|
updateProcess.state.addListener((observableValue, oldValue, newValue) -> applyUpdateState(newValue));
|
||||||
applyUpdateState(updateProcess.state.get());
|
applyUpdateState(updateProcess.state.get());
|
||||||
|
|
|
@ -31,7 +31,7 @@
|
||||||
<Insets bottom="10.0" left="25.0" top="30.0" right="25"/>
|
<Insets bottom="10.0" left="25.0" top="30.0" right="25"/>
|
||||||
</padding>
|
</padding>
|
||||||
|
|
||||||
<TitledGroupBg text="Network information" GridPane.rowSpan="8"/>
|
<TitledGroupBg text="Bitcoin network" GridPane.rowSpan="3"/>
|
||||||
|
|
||||||
<Label text="Bitcoin network type:" GridPane.rowIndex="0">
|
<Label text="Bitcoin network type:" GridPane.rowIndex="0">
|
||||||
<GridPane.margin>
|
<GridPane.margin>
|
||||||
|
@ -45,46 +45,54 @@
|
||||||
</GridPane.margin>
|
</GridPane.margin>
|
||||||
</TextField>
|
</TextField>
|
||||||
|
|
||||||
<Label text="Bitcoin network connected peers:" GridPane.rowIndex="1"/>
|
<Label text="Select Network:" GridPane.rowIndex="1"/>
|
||||||
<TextField fx:id="connectedPeersBTC" GridPane.rowIndex="1" GridPane.columnIndex="1"
|
<ComboBox fx:id="netWorkComboBox" onAction="#onSelectNetwork" GridPane.rowIndex="1" GridPane.columnIndex="1"/>
|
||||||
|
|
||||||
|
<Label text="Bitcoin network connected peers:" GridPane.rowIndex="2"/>
|
||||||
|
<TextField fx:id="connectedPeersBTC" GridPane.rowIndex="2" GridPane.columnIndex="1"
|
||||||
mouseTransparent="true" focusTraversable="false"/>
|
mouseTransparent="true" focusTraversable="false"/>
|
||||||
|
|
||||||
|
|
||||||
<Label text="P2P network connection:" GridPane.rowIndex="2"/>
|
<TitledGroupBg text="P2P network" GridPane.rowIndex="3" GridPane.rowSpan="5">
|
||||||
<TextField fx:id="connectionType" GridPane.rowIndex="2" GridPane.columnIndex="1"
|
<padding>
|
||||||
mouseTransparent="true" focusTraversable="false"/>
|
<Insets top="50.0"/>
|
||||||
|
</padding>
|
||||||
<Label text="P2P network connected peers:" GridPane.rowIndex="3"/>
|
|
||||||
<TextField fx:id="connectedPeersP2P" GridPane.rowIndex="3" GridPane.columnIndex="1"
|
|
||||||
mouseTransparent="true" focusTraversable="false"/>
|
|
||||||
|
|
||||||
<Label text="My external visible P2P network address:" GridPane.rowIndex="4"/>
|
|
||||||
<TextField fx:id="nodeAddress" GridPane.rowIndex="4" GridPane.columnIndex="1"
|
|
||||||
mouseTransparent="true" focusTraversable="false"/>
|
|
||||||
|
|
||||||
<Label text="P2P bootstrap node address:" GridPane.rowIndex="5">
|
|
||||||
<GridPane.margin>
|
<GridPane.margin>
|
||||||
<Insets bottom="-15"/>
|
<Insets bottom="-10" left="-10" right="-10" top="30"/>
|
||||||
|
</GridPane.margin>
|
||||||
|
</TitledGroupBg>
|
||||||
|
|
||||||
|
<Label text="P2P network connection:" GridPane.rowIndex="3">
|
||||||
|
<GridPane.margin>
|
||||||
|
<Insets top="50.0"/>
|
||||||
</GridPane.margin>
|
</GridPane.margin>
|
||||||
</Label>
|
</Label>
|
||||||
<TextField fx:id="bootstrapNodeAddress" GridPane.rowIndex="5" GridPane.columnIndex="1"
|
<TextField fx:id="connectionType" GridPane.rowIndex="3" GridPane.columnIndex="1"
|
||||||
mouseTransparent="true" focusTraversable="false">
|
mouseTransparent="true" focusTraversable="false">
|
||||||
<GridPane.margin>
|
<GridPane.margin>
|
||||||
<Insets bottom="-15"/>
|
<Insets top="50.0"/>
|
||||||
</GridPane.margin>
|
</GridPane.margin>
|
||||||
</TextField>
|
</TextField>
|
||||||
|
|
||||||
|
<Label text="Use UPnP:" GridPane.rowIndex="4"/>
|
||||||
|
<CheckBox fx:id="useUPnP" onAction="#onSelectUPnP" GridPane.rowIndex="4" GridPane.columnIndex="1"/>
|
||||||
|
|
||||||
|
<Label text="P2P network connected peers:" GridPane.rowIndex="5"/>
|
||||||
|
<TextField fx:id="connectedPeersP2P" GridPane.rowIndex="5" GridPane.columnIndex="1"
|
||||||
|
mouseTransparent="true" focusTraversable="false"/>
|
||||||
|
|
||||||
|
<Label text="My external visible P2P network address:" GridPane.rowIndex="6"/>
|
||||||
|
<TextField fx:id="nodeAddress" GridPane.rowIndex="6" GridPane.columnIndex="1"
|
||||||
|
mouseTransparent="true" focusTraversable="false"/>
|
||||||
|
|
||||||
|
<Label text="P2P bootstrap node address:" GridPane.rowIndex="7"/>
|
||||||
|
<TextField fx:id="bootstrapNodeAddress" GridPane.rowIndex="7" GridPane.columnIndex="1"
|
||||||
|
mouseTransparent="true" focusTraversable="false"/>
|
||||||
|
|
||||||
<columnConstraints>
|
<columnConstraints>
|
||||||
<ColumnConstraints hgrow="SOMETIMES" halignment="RIGHT" minWidth="200.0"/>
|
<ColumnConstraints hgrow="SOMETIMES" halignment="RIGHT" minWidth="200.0"/>
|
||||||
<ColumnConstraints hgrow="ALWAYS" minWidth="300.0"/>
|
<ColumnConstraints hgrow="ALWAYS" minWidth="300.0"/>
|
||||||
</columnConstraints>
|
</columnConstraints>
|
||||||
|
|
||||||
<rowConstraints>
|
|
||||||
<RowConstraints vgrow="NEVER"/>
|
|
||||||
<RowConstraints vgrow="NEVER"/>
|
|
||||||
<RowConstraints vgrow="NEVER"/>
|
|
||||||
</rowConstraints>
|
|
||||||
|
|
||||||
</GridPane>
|
</GridPane>
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -17,18 +17,30 @@
|
||||||
|
|
||||||
package io.bitsquare.gui.main.settings.network;
|
package io.bitsquare.gui.main.settings.network;
|
||||||
|
|
||||||
|
import io.bitsquare.app.BitsquareApp;
|
||||||
import io.bitsquare.btc.BitcoinNetwork;
|
import io.bitsquare.btc.BitcoinNetwork;
|
||||||
import io.bitsquare.btc.WalletService;
|
import io.bitsquare.btc.WalletService;
|
||||||
import io.bitsquare.gui.common.view.FxmlView;
|
import io.bitsquare.gui.common.view.FxmlView;
|
||||||
import io.bitsquare.gui.common.view.InitializableView;
|
import io.bitsquare.gui.common.view.InitializableView;
|
||||||
|
import io.bitsquare.gui.components.Popups;
|
||||||
import io.bitsquare.gui.util.BSFormatter;
|
import io.bitsquare.gui.util.BSFormatter;
|
||||||
|
import io.bitsquare.locale.BSResources;
|
||||||
import io.bitsquare.p2p.ClientNode;
|
import io.bitsquare.p2p.ClientNode;
|
||||||
|
import io.bitsquare.user.Preferences;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import javafx.collections.FXCollections;
|
||||||
|
import javafx.event.ActionEvent;
|
||||||
import javafx.fxml.FXML;
|
import javafx.fxml.FXML;
|
||||||
import javafx.scene.control.*;
|
import javafx.scene.control.*;
|
||||||
|
|
||||||
|
import org.controlsfx.control.action.AbstractAction;
|
||||||
|
import org.controlsfx.control.action.Action;
|
||||||
|
|
||||||
import static javafx.beans.binding.Bindings.createStringBinding;
|
import static javafx.beans.binding.Bindings.createStringBinding;
|
||||||
|
|
||||||
@FxmlView
|
@FxmlView
|
||||||
|
@ -36,14 +48,19 @@ public class NetworkSettingsView extends InitializableView {
|
||||||
|
|
||||||
private final String bitcoinNetworkString;
|
private final String bitcoinNetworkString;
|
||||||
private final WalletService walletService;
|
private final WalletService walletService;
|
||||||
|
private final Preferences preferences;
|
||||||
private final ClientNode clientNode;
|
private final ClientNode clientNode;
|
||||||
|
|
||||||
@FXML TextField bitcoinNetwork, connectionType, nodeAddress, bootstrapNodeAddress, connectedPeersBTC, connectedPeersP2P;
|
@FXML TextField bitcoinNetwork, connectionType, nodeAddress, bootstrapNodeAddress, connectedPeersBTC, connectedPeersP2P;
|
||||||
|
@FXML CheckBox useUPnP;
|
||||||
|
@FXML ComboBox<BitcoinNetwork> netWorkComboBox;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public NetworkSettingsView(BitcoinNetwork bitcoinNetwork, WalletService walletService, ClientNode clientNode, BSFormatter formatter) {
|
public NetworkSettingsView(WalletService walletService, ClientNode clientNode, Preferences preferences, BSFormatter
|
||||||
|
formatter) {
|
||||||
this.walletService = walletService;
|
this.walletService = walletService;
|
||||||
this.bitcoinNetworkString = formatter.formatBitcoinNetwork(bitcoinNetwork);
|
this.preferences = preferences;
|
||||||
|
this.bitcoinNetworkString = formatter.formatBitcoinNetwork(preferences.getBitcoinNetwork());
|
||||||
this.clientNode = clientNode;
|
this.clientNode = clientNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,6 +73,46 @@ public class NetworkSettingsView extends InitializableView {
|
||||||
connectedPeersP2P.textProperty().bind(createStringBinding(() -> String.valueOf(clientNode.numPeersProperty().get()), clientNode.numPeersProperty()));
|
connectedPeersP2P.textProperty().bind(createStringBinding(() -> String.valueOf(clientNode.numPeersProperty().get()), clientNode.numPeersProperty()));
|
||||||
nodeAddress.setText(clientNode.getAddress().toString());
|
nodeAddress.setText(clientNode.getAddress().toString());
|
||||||
bootstrapNodeAddress.setText(clientNode.getBootstrapNodeAddress().toString());
|
bootstrapNodeAddress.setText(clientNode.getBootstrapNodeAddress().toString());
|
||||||
|
|
||||||
|
useUPnP.setSelected(preferences.getUseUPnP());
|
||||||
|
|
||||||
|
netWorkComboBox.setItems(FXCollections.observableArrayList(BitcoinNetwork.values()));
|
||||||
|
netWorkComboBox.getSelectionModel().select(preferences.getBitcoinNetwork());
|
||||||
|
}
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
void onSelectUPnP() {
|
||||||
|
preferences.setUseUPnP(useUPnP.isSelected());
|
||||||
|
}
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
void onSelectNetwork() {
|
||||||
|
preferences.setBitcoinNetwork(netWorkComboBox.getSelectionModel().getSelectedItem());
|
||||||
|
|
||||||
|
List<Action> actions = new ArrayList<>();
|
||||||
|
actions.add(new AbstractAction(BSResources.get("shared.no")) {
|
||||||
|
@Override
|
||||||
|
public void handle(ActionEvent actionEvent) {
|
||||||
|
getProperties().put("type", "NO");
|
||||||
|
org.controlsfx.dialog.Dialog.Actions.NO.handle(actionEvent);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
actions.add(new AbstractAction(BSResources.get("shared.yes")) {
|
||||||
|
@Override
|
||||||
|
public void handle(ActionEvent actionEvent) {
|
||||||
|
getProperties().put("type", "YES");
|
||||||
|
org.controlsfx.dialog.Dialog.Actions.YES.handle(actionEvent);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Action response = Popups.openConfirmPopup("Info", null,
|
||||||
|
"You need to restart the application to apply the change of the Bitcoin network." +
|
||||||
|
"\n\nDo you want to shutdown now?",
|
||||||
|
actions);
|
||||||
|
|
||||||
|
if (Popups.isYes(response))
|
||||||
|
BitsquareApp.shutDownHandler.run();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
|
|
||||||
package io.bitsquare.gui.util.validation;
|
package io.bitsquare.gui.util.validation;
|
||||||
|
|
||||||
import io.bitsquare.btc.BitcoinNetwork;
|
import io.bitsquare.user.Preferences;
|
||||||
|
|
||||||
import org.bitcoinj.core.Address;
|
import org.bitcoinj.core.Address;
|
||||||
import org.bitcoinj.core.AddressFormatException;
|
import org.bitcoinj.core.AddressFormatException;
|
||||||
|
@ -26,11 +26,11 @@ import javax.inject.Inject;
|
||||||
|
|
||||||
public final class BtcAddressValidator extends InputValidator {
|
public final class BtcAddressValidator extends InputValidator {
|
||||||
|
|
||||||
private final BitcoinNetwork bitcoinNetwork;
|
private Preferences preferences;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public BtcAddressValidator(BitcoinNetwork bitcoinNetwork) {
|
public BtcAddressValidator(Preferences preferences) {
|
||||||
this.bitcoinNetwork = bitcoinNetwork;
|
this.preferences = preferences;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -45,7 +45,7 @@ public final class BtcAddressValidator extends InputValidator {
|
||||||
|
|
||||||
private ValidationResult validateBtcAddress(String input) {
|
private ValidationResult validateBtcAddress(String input) {
|
||||||
try {
|
try {
|
||||||
new Address(bitcoinNetwork.getParameters(), input);
|
new Address(preferences.getBitcoinNetwork().getParameters(), input);
|
||||||
return new ValidationResult(true);
|
return new ValidationResult(true);
|
||||||
} catch (AddressFormatException e) {
|
} catch (AddressFormatException e) {
|
||||||
return new ValidationResult(false, "Bitcoin address is a valid format");
|
return new ValidationResult(false, "Bitcoin address is a valid format");
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue