Use separate dirs for version and btc network, bootstrap to all bootstrap nodes, change config of bootstrap node

This commit is contained in:
Manfred Karrer 2015-05-18 17:05:53 +02:00
parent 7a9de65e86
commit fc3634af7b
29 changed files with 285 additions and 272 deletions

View file

@ -18,14 +18,16 @@
package io.bitsquare.app.bootstrap; package io.bitsquare.app.bootstrap;
import io.bitsquare.app.Logging; import io.bitsquare.app.Logging;
import io.bitsquare.app.Version;
import io.bitsquare.p2p.BootstrapNodes; import io.bitsquare.p2p.BootstrapNodes;
import io.bitsquare.p2p.Node; import io.bitsquare.p2p.Node;
import java.util.Collection; import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import net.tomp2p.connection.ChannelClientConfiguration;
import net.tomp2p.connection.ChannelServerConfiguration;
import net.tomp2p.dht.PeerBuilderDHT; import net.tomp2p.dht.PeerBuilderDHT;
import net.tomp2p.dht.PeerDHT;
import net.tomp2p.nat.PeerBuilderNAT; import net.tomp2p.nat.PeerBuilderNAT;
import net.tomp2p.p2p.Peer; import net.tomp2p.p2p.Peer;
import net.tomp2p.p2p.PeerBuilder; import net.tomp2p.p2p.PeerBuilder;
@ -37,13 +39,12 @@ import net.tomp2p.peers.PeerStatistic;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import io.netty.util.concurrent.DefaultEventExecutorGroup;
import org.springframework.core.env.Environment; import org.springframework.core.env.Environment;
public class BootstrapNode { public class BootstrapNode {
private static final Logger log = LoggerFactory.getLogger(BootstrapNode.class); private static final Logger log = LoggerFactory.getLogger(BootstrapNode.class);
private static final String VERSION = "0.1.3";
private static Peer peer = null; private static Peer peer = null;
private final Environment env; private final Environment env;
@ -53,29 +54,31 @@ public class BootstrapNode {
this.env = env; this.env = env;
} }
public void start() { public void start() {
String name = env.getProperty(Node.NAME_KEY, BootstrapNodes.getLocalhostNode().getName()); BootstrapNodes bootstrapNodes = new BootstrapNodes();
int p2pId = env.getProperty(Node.P2P_ID_KEY, Integer.class, BootstrapNodes.getLocalhostNode().getP2pId()); int p2pId = env.getProperty(Node.P2P_ID_KEY, Integer.class, Node.REG_TEST_P2P_ID); // use regtest as default
int port = env.getProperty(Node.PORT_KEY, Integer.class, BootstrapNodes.getLocalhostNode().getPort()); bootstrapNodes.initWithNetworkId(p2pId);
String name = env.getProperty(Node.NAME_KEY, bootstrapNodes.getLocalhostNode().getName());
int port = env.getProperty(Node.PORT_KEY, Integer.class, bootstrapNodes.getLocalhostNode().getPort());
Logging.setup(name + "_" + port); Logging.setup(name + "_" + port);
try { try {
Number160 peerId = Number160.createHash(name); Number160 peerId = Number160.createHash(name);
/*
DefaultEventExecutorGroup eventExecutorGroup = new DefaultEventExecutorGroup(50); DefaultEventExecutorGroup eventExecutorGroup = new DefaultEventExecutorGroup(50);
ChannelClientConfiguration clientConf = PeerBuilder.createDefaultChannelClientConfiguration(); ChannelClientConfiguration clientConf = PeerBuilder.createDefaultChannelClientConfiguration();
clientConf.pipelineFilter(new PeerBuilder.EventExecutorGroupFilter(eventExecutorGroup)); clientConf.pipelineFilter(new PeerBuilder.EventExecutorGroupFilter(eventExecutorGroup));
ChannelServerConfiguration serverConf = PeerBuilder.createDefaultChannelServerConfiguration(); ChannelServerConfiguration serverConf = PeerBuilder.createDefaultChannelServerConfiguration();
serverConf.pipelineFilter(new PeerBuilder.EventExecutorGroupFilter(eventExecutorGroup)); serverConf.pipelineFilter(new PeerBuilder.EventExecutorGroupFilter(eventExecutorGroup));
serverConf.connectionTimeoutTCPMillis(5000);*/ serverConf.connectionTimeoutTCPMillis(5000);
peer = new PeerBuilder(peerId) peer = new PeerBuilder(peerId)
.ports(port) .ports(port)
.p2pId(p2pId) .p2pId(p2pId)
/* .channelClientConfiguration(clientConf) .channelClientConfiguration(clientConf)
.channelServerConfiguration(serverConf)*/ .channelServerConfiguration(serverConf)
.start(); .start();
/*peer.objectDataReply((sender, request) -> { /*peer.objectDataReply((sender, request) -> {
@ -83,70 +86,57 @@ public class BootstrapNode {
return "pong"; return "pong";
});*/ });*/
PeerDHT peerDHT = new PeerBuilderDHT(peer).start(); new PeerBuilderDHT(peer).start();
new PeerBuilderNAT(peer).start(); new PeerBuilderNAT(peer).start();
final int _port = port; final int _port = port;
if (!name.equals(BootstrapNodes.getLocalhostNode().getName())) { if (!name.equals(bootstrapNodes.getLocalhostNode().getName())) {
Collection<PeerAddress> bootstrapNodes = BootstrapNodes.getAllBootstrapNodes(p2pId).stream().filter(e -> !e.getName().equals(name)) List<Node> bootstrapNodesExcludingMyself = bootstrapNodes.getBootstrapNodes().stream().filter(e -> !e.getName().equals
(name)).collect(Collectors.toList());
log.info("Bootstrapping to bootstrapNodes " + bootstrapNodesExcludingMyself);
long ts = System.currentTimeMillis();
List<PeerAddress> bootstrapAddressesExcludingMyself = bootstrapNodesExcludingMyself.stream()
.map(e -> e.toPeerAddressWithPort(_port)).collect(Collectors.toList()); .map(e -> e.toPeerAddressWithPort(_port)).collect(Collectors.toList());
peer.bootstrap().bootstrapTo(bootstrapAddressesExcludingMyself).start().awaitUninterruptibly();
log.info("Bootstrapping to " + bootstrapNodes.size() + " bootstrapNode(s)"); log.info("Bootstrapping done after {} msec", System.currentTimeMillis() - ts);
log.info("Bootstrapping bootstrapNodes " + bootstrapNodes);
peer.bootstrap().bootstrapTo(bootstrapNodes).start().awaitUninterruptibly();
} }
else { else {
log.info("We are localhost, we do not bootstrap to other nodes"); log.info("When using localhost we do not bootstrap to other nodes");
} }
peer.peerBean().peerMap().addPeerMapChangeListener(new PeerMapChangeListener() { peer.peerBean().peerMap().addPeerMapChangeListener(new PeerMapChangeListener() {
@Override @Override
public void peerInserted(PeerAddress peerAddress, boolean verified) { public void peerInserted(PeerAddress peerAddress, boolean verified) {
try {
log.info("Peer inserted: peerAddress=" + peerAddress + ", verified=" + verified); log.info("Peer inserted: peerAddress=" + peerAddress + ", verified=" + verified);
} catch (Throwable t) {
log.error("Exception at peerInserted " + t.getMessage());
}
} }
@Override @Override
public void peerRemoved(PeerAddress peerAddress, PeerStatistic peerStatistics) { public void peerRemoved(PeerAddress peerAddress, PeerStatistic peerStatistics) {
try {
log.info("Peer removed: peerAddress=" + peerAddress + ", peerStatistics=" + peerStatistics); log.info("Peer removed: peerAddress=" + peerAddress + ", peerStatistics=" + peerStatistics);
} catch (Throwable t) {
log.error("Exception at peerRemoved " + t.getMessage());
}
} }
@Override @Override
public void peerUpdated(PeerAddress peerAddress, PeerStatistic peerStatistics) { public void peerUpdated(PeerAddress peerAddress, PeerStatistic peerStatistics) {
try {
//log.info("Peer updated: peerAddress=" + peerAddress + ", peerStatistics=" + peerStatistics); //log.info("Peer updated: peerAddress=" + peerAddress + ", peerStatistics=" + peerStatistics);
} catch (Throwable t) {
log.error("Exception at peerUpdated " + t.getMessage());
}
} }
}); });
log.info("Bootstrap node started with name=" + name + " ,p2pId=" + p2pId + " ,port=" + port + " and version=" + VERSION); log.info("Bootstrap node started with name=" + name + " ,p2pId=" + p2pId + " ,port=" + port +
" and network protocol version=" + Version.NETWORK_PROTOCOL_VERSION);
new Thread(() -> { new Thread(() -> {
while (true) { while (true) {
if (peer.peerBean().peerMap().all().size() > 0) { if (peer.peerBean().peerMap().all().size() > 0) {
noPeersInfoPrinted = false; noPeersInfoPrinted = false;
try {
log.info("Number of peers online = " + peer.peerBean().peerMap().all().size()); log.info("Number of peers online = " + peer.peerBean().peerMap().all().size());
for (PeerAddress peerAddress : peer.peerBean().peerMap().all()) { for (PeerAddress peerAddress : peer.peerBean().peerMap().all()) {
log.info("Peer: " + peerAddress.toString()); log.info("Peer: " + peerAddress.toString());
} }
} catch (Throwable t) {
log.error("Exception at run loop " + t.getMessage());
}
} }
else if (noPeersInfoPrinted) { else if (noPeersInfoPrinted) {
log.info("No peers online"); log.info("No peers online");
noPeersInfoPrinted = true; noPeersInfoPrinted = true;
} }
try { try {
Thread.sleep(2000); Thread.sleep(10000);
} catch (InterruptedException e) { } catch (InterruptedException e) {
e.printStackTrace(); e.printStackTrace();
return; return;

View file

@ -32,14 +32,16 @@ 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.getLocalhostNode().getName())) BootstrapNodes bootstrapNodes = new BootstrapNodes();
bootstrapNodes.initWithNetworkId(Node.REG_TEST_P2P_ID); // use regtest as default
parser.accepts(Node.NAME_KEY, description("Name of this node", bootstrapNodes.getLocalhostNode().getName()))
.withRequiredArg() .withRequiredArg()
.ofType(String.class); .ofType(String.class);
parser.accepts(Node.P2P_ID_KEY, description("P2P network ID", parser.accepts(Node.P2P_ID_KEY, description("P2P network ID",
BootstrapNodes.getLocalhostNode().getP2pId())) bootstrapNodes.getLocalhostNode().getP2pId()))
.withRequiredArg() .withRequiredArg()
.ofType(int.class); .ofType(int.class);
parser.accepts(Node.PORT_KEY, description("Port to listen on", BootstrapNodes.getLocalhostNode().getPort())) parser.accepts(Node.PORT_KEY, description("Port to listen on", bootstrapNodes.getLocalhostNode().getPort()))
.withRequiredArg() .withRequiredArg()
.ofType(int.class); .ofType(int.class);
} }

View file

@ -18,6 +18,7 @@
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;
@ -26,10 +27,19 @@ import io.bitsquare.storage.Storage;
import io.bitsquare.util.Utilities; import io.bitsquare.util.Utilities;
import io.bitsquare.util.spring.JOptCommandLinePropertySource; import io.bitsquare.util.spring.JOptCommandLinePropertySource;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.util.Properties; import java.util.Properties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import joptsimple.OptionSet; import joptsimple.OptionSet;
import org.springframework.core.env.MutablePropertySources; import org.springframework.core.env.MutablePropertySources;
import org.springframework.core.env.PropertiesPropertySource; import org.springframework.core.env.PropertiesPropertySource;
@ -43,7 +53,9 @@ import org.springframework.core.io.support.ResourcePropertySource;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
public class BitsquareEnvironment extends StandardEnvironment { public class BitsquareEnvironment extends StandardEnvironment {
private static final Logger log = LoggerFactory.getLogger(BitsquareEnvironment.class);
private static final String BITCOIN_NETWORK_PROP = "bitcoinNetwork.properties";
public static final String USER_DATA_DIR_KEY = "user.data.dir"; public static final String USER_DATA_DIR_KEY = "user.data.dir";
public static final String DEFAULT_USER_DATA_DIR = defaultUserDataDir(); public static final String DEFAULT_USER_DATA_DIR = defaultUserDataDir();
@ -52,7 +64,7 @@ public class BitsquareEnvironment extends StandardEnvironment {
public static final String DEFAULT_APP_NAME = "Bitsquare"; public static final String DEFAULT_APP_NAME = "Bitsquare";
public static final String APP_DATA_DIR_KEY = "app.data.dir"; public static final String APP_DATA_DIR_KEY = "app.data.dir";
public static final String DEFAULT_APP_DATA_DIR = appDataDir(DEFAULT_USER_DATA_DIR, DEFAULT_APP_NAME); public static final String DEFAULT_APP_DATA_DIR = appDataDir(DEFAULT_USER_DATA_DIR, DEFAULT_APP_NAME, BitcoinNetwork.DEFAULT, Version.VERSION);
public static final String APP_DATA_DIR_CLEAN_KEY = "app.data.dir.clean"; public static final String APP_DATA_DIR_CLEAN_KEY = "app.data.dir.clean";
public static final String DEFAULT_APP_DATA_DIR_CLEAN = "false"; public static final String DEFAULT_APP_DATA_DIR_CLEAN = "false";
@ -60,12 +72,13 @@ public class BitsquareEnvironment extends StandardEnvironment {
static final String BITSQUARE_COMMANDLINE_PROPERTY_SOURCE_NAME = "bitsquareCommandLineProperties"; static final String BITSQUARE_COMMANDLINE_PROPERTY_SOURCE_NAME = "bitsquareCommandLineProperties";
static final String BITSQUARE_APP_DIR_PROPERTY_SOURCE_NAME = "bitsquareAppDirProperties"; static final String BITSQUARE_APP_DIR_PROPERTY_SOURCE_NAME = "bitsquareAppDirProperties";
static final String BITSQUARE_HOME_DIR_PROPERTY_SOURCE_NAME = "bitsquareHomeDirProperties"; static final String BITSQUARE_HOME_DIR_PROPERTY_SOURCE_NAME = "bitsquareHomeDirProperties";
static final String BITSQUARE_CLASSPATH_PROPERTY_SOURCE_NAME = "bitsquareClasspathProperties"; public static final String BITSQUARE_CLASSPATH_PROPERTY_SOURCE_NAME = "bitsquareClasspathProperties";
static final String BITSQUARE_DEFAULT_PROPERTY_SOURCE_NAME = "bitsquareDefaultProperties"; static final String BITSQUARE_DEFAULT_PROPERTY_SOURCE_NAME = "bitsquareDefaultProperties";
private final ResourceLoader resourceLoader = new DefaultResourceLoader(); private final ResourceLoader resourceLoader = new DefaultResourceLoader();
protected final String appName; protected final String appName;
protected final String userDataDir;
protected final String appDataDir; protected final String appDataDir;
protected final String bootstrapNodePort; protected final String bootstrapNodePort;
@ -73,20 +86,60 @@ public class BitsquareEnvironment extends StandardEnvironment {
this(new JOptCommandLinePropertySource(BITSQUARE_COMMANDLINE_PROPERTY_SOURCE_NAME, checkNotNull(options))); this(new JOptCommandLinePropertySource(BITSQUARE_COMMANDLINE_PROPERTY_SOURCE_NAME, checkNotNull(options)));
} }
public BitcoinNetwork getBtcNetworkProperty() {
String dirString = Paths.get(userDataDir, appName, Version.VERSION).toString();
String fileString = Paths.get(dirString, BITCOIN_NETWORK_PROP).toString();
File dir = new File(dirString);
File file = new File(fileString);
if (!dir.exists())
dir.mkdirs();
if (!file.exists()) {
try {
file.createNewFile();
} catch (Throwable e) {
log.error(e.getMessage());
}
}
try (InputStream fileInputStream = new FileInputStream(file)) {
Properties properties = new Properties();
properties.load(fileInputStream);
String bitcoinNetwork = properties.getProperty("bitcoinNetwork", BitcoinNetwork.DEFAULT.name());
return BitcoinNetwork.valueOf(bitcoinNetwork);
} catch (Throwable e) {
e.printStackTrace();
log.error(e.getMessage());
return BitcoinNetwork.DEFAULT;
}
}
public void setBitcoinNetwork(BitcoinNetwork bitcoinNetwork) {
String path = Paths.get(userDataDir, appName, Version.VERSION, BITCOIN_NETWORK_PROP).toString();
File file = new File(path);
try (FileOutputStream fos = new FileOutputStream(file)) {
Properties properties = new Properties();
properties.setProperty("bitcoinNetwork", bitcoinNetwork.name());
properties.store(fos, null);
} catch (IOException e) {
e.printStackTrace();
log.error(e.getMessage());
}
}
protected BitsquareEnvironment(PropertySource commandLineProperties) { protected BitsquareEnvironment(PropertySource commandLineProperties) {
String userDataDir = commandLineProperties.containsProperty(USER_DATA_DIR_KEY) ? userDataDir = commandLineProperties.containsProperty(USER_DATA_DIR_KEY) ?
(String) commandLineProperties.getProperty(USER_DATA_DIR_KEY) : (String) commandLineProperties.getProperty(USER_DATA_DIR_KEY) :
DEFAULT_USER_DATA_DIR; DEFAULT_USER_DATA_DIR;
this.appName = commandLineProperties.containsProperty(APP_NAME_KEY) ? appName = commandLineProperties.containsProperty(APP_NAME_KEY) ?
(String) commandLineProperties.getProperty(APP_NAME_KEY) : (String) commandLineProperties.getProperty(APP_NAME_KEY) :
DEFAULT_APP_NAME; DEFAULT_APP_NAME;
this.appDataDir = commandLineProperties.containsProperty(APP_DATA_DIR_KEY) ? appDataDir = commandLineProperties.containsProperty(APP_DATA_DIR_KEY) ?
(String) commandLineProperties.getProperty(APP_DATA_DIR_KEY) : (String) commandLineProperties.getProperty(APP_DATA_DIR_KEY) :
appDataDir(userDataDir, appName); appDataDir(userDataDir, appName, getBtcNetworkProperty(), Version.VERSION);
this.bootstrapNodePort = commandLineProperties.containsProperty(TomP2PModule.BOOTSTRAP_NODE_PORT_KEY) ? bootstrapNodePort = commandLineProperties.containsProperty(TomP2PModule.BOOTSTRAP_NODE_PORT_KEY) ?
(String) commandLineProperties.getProperty(TomP2PModule.BOOTSTRAP_NODE_PORT_KEY) : "-1"; (String) commandLineProperties.getProperty(TomP2PModule.BOOTSTRAP_NODE_PORT_KEY) : "-1";
MutablePropertySources propertySources = this.getPropertySources(); MutablePropertySources propertySources = this.getPropertySources();
@ -129,7 +182,6 @@ public class BitsquareEnvironment extends StandardEnvironment {
protected PropertySource<?> defaultProperties() { protected PropertySource<?> defaultProperties() {
return new PropertiesPropertySource(BITSQUARE_DEFAULT_PROPERTY_SOURCE_NAME, new Properties() { return new PropertiesPropertySource(BITSQUARE_DEFAULT_PROPERTY_SOURCE_NAME, new Properties() {
private static final long serialVersionUID = -8478089705207326165L; private static final long serialVersionUID = -8478089705207326165L;
{ {
setProperty(APP_DATA_DIR_KEY, appDataDir); setProperty(APP_DATA_DIR_KEY, appDataDir);
setProperty(APP_DATA_DIR_CLEAN_KEY, DEFAULT_APP_DATA_DIR_CLEAN); setProperty(APP_DATA_DIR_CLEAN_KEY, DEFAULT_APP_DATA_DIR_CLEAN);
@ -149,7 +201,6 @@ public class BitsquareEnvironment extends StandardEnvironment {
}); });
} }
private static String defaultUserDataDir() { private static String defaultUserDataDir() {
if (Utilities.isWindows()) if (Utilities.isWindows())
return System.getenv("APPDATA"); return System.getenv("APPDATA");
@ -159,7 +210,7 @@ public class BitsquareEnvironment extends StandardEnvironment {
return Paths.get(System.getProperty("user.home"), ".local", "share").toString(); return Paths.get(System.getProperty("user.home"), ".local", "share").toString();
} }
private static String appDataDir(String userDataDir, String appName) { private static String appDataDir(String userDataDir, String appName, BitcoinNetwork bitcoinNetwork, String version) {
return Paths.get(userDataDir, appName).toString(); return Paths.get(userDataDir, appName, version, bitcoinNetwork.name().toLowerCase()).toString();
} }
} }

View file

@ -136,7 +136,7 @@ public class WalletService {
this.addressEntryList = addressEntryList; this.addressEntryList = addressEntryList;
this.params = preferences.getBitcoinNetwork().getParameters(); this.params = preferences.getBitcoinNetwork().getParameters();
this.cryptoService = cryptoService; this.cryptoService = cryptoService;
this.walletDir = new File(walletDir, preferences.getBitcoinNetwork().toString().toLowerCase()); this.walletDir = new File(walletDir, "bitcoin");
this.walletPrefix = walletPrefix; this.walletPrefix = walletPrefix;
this.userAgent = userAgent; this.userAgent = userAgent;
} }
@ -176,6 +176,7 @@ public class WalletService {
// Now configure and start the appkit. This will take a second or two - we could show a temporary splash screen // Now configure and start the appkit. This will take a second or two - we could show a temporary splash screen
// or progress widget to keep the user engaged whilst we initialise, but we don't. // or progress widget to keep the user engaged whilst we initialise, but we don't.
if (params == RegTestParams.get()) { if (params == RegTestParams.get()) {
log.debug("regTestHost " + regTestHost);
if (regTestHost == RegTestHost.REG_TEST_SERVER) { if (regTestHost == RegTestHost.REG_TEST_SERVER) {
try { try {
walletAppKit.setPeerNodes(new PeerAddress(InetAddress.getByName(RegTestHost.SERVER_IP), params.getPort())); walletAppKit.setPeerNodes(new PeerAddress(InetAddress.getByName(RegTestHost.SERVER_IP), params.getPort()));

View file

@ -19,83 +19,121 @@ package io.bitsquare.p2p;
import io.bitsquare.BitsquareException; import io.bitsquare.BitsquareException;
import com.google.inject.name.Named;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Random; import java.util.Random;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import javax.inject.Inject;
import net.tomp2p.peers.Number160;
import net.tomp2p.peers.PeerAddress;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; 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 String BOOTSTRAP_NODE_KEY = "bootstrapNode";
private static final List<Node> bootstrapNodes = Arrays.asList( private final List<Node> rawBootstrapNodes = Arrays.asList(
Node.at("digitalocean1.bitsquare.io", "188.226.179.109"), Node.rawNodeAt("digitalocean1.bitsquare.io", "188.226.179.109"),
Node.at("aws1.bitsquare.io", "52.24.144.42"), Node.rawNodeAt("aws1.bitsquare.io", "52.24.144.42"),
Node.at("aws2.bitsquare.io", "52.11.125.194") Node.rawNodeAt("aws2.bitsquare.io", "52.11.125.194")
); );
private static Node selectedNode; private Node rawLocalhostNode = Node.rawNodeAt("localhost", "127.0.0.1");
public static List<Node> getAllBootstrapNodes(int p2pId) {
private Node preferredBootstrapNode;
private List<Node> bootstrapNodes;
private Node localhostNode;
private int p2pId;
private boolean inited;
@Inject
public BootstrapNodes(@Named(BOOTSTRAP_NODE_KEY) Node preferredBootstrapNode) {
// preferredBootstrapNode need to be fully defined to get accepted (name, IP, p2pId, port)
if (preferredBootstrapNode.getName() != null
&& preferredBootstrapNode.getIp() != null
&& preferredBootstrapNode.getP2pId() != -1
&& preferredBootstrapNode.getPort() != -1) {
this.preferredBootstrapNode = preferredBootstrapNode;
}
else if (preferredBootstrapNode.getName() != null
|| preferredBootstrapNode.getIp() != null
|| preferredBootstrapNode.getP2pId() != -1
|| preferredBootstrapNode.getPort() != -1) {
log.debug("preferredBootstrapNode not fully defined (name, IP, p2pId, port). preferredBootstrapNode=" + preferredBootstrapNode);
}
}
public BootstrapNodes() {
}
public void initWithNetworkId(int p2pId) {
if (!inited) {
inited = true;
this.p2pId = p2pId;
if (preferredBootstrapNode != null) {
bootstrapNodes = Arrays.asList(preferredBootstrapNode);
}
else {
switch (p2pId) { switch (p2pId) {
case Node.MAIN_NET_P2P_ID: case Node.MAIN_NET_P2P_ID:
return bootstrapNodes.stream().map(e -> e.withP2pIdAndPort(Node.MAIN_NET_P2P_ID, Node.MAIN_NET_PORT)).collect(Collectors.toList()); bootstrapNodes = rawBootstrapNodes.stream()
.map(e -> e.withP2pIdAndPort(Node.MAIN_NET_P2P_ID, Node.MAIN_NET_PORT)).collect(Collectors.toList());
localhostNode = rawLocalhostNode.withP2pIdAndPort(Node.MAIN_NET_P2P_ID, Node.MAIN_NET_PORT);
break;
case Node.TEST_NET_P2P_ID: case Node.TEST_NET_P2P_ID:
return bootstrapNodes.stream().map(e -> e.withP2pIdAndPort(Node.TEST_NET_P2P_ID, Node.TEST_NET_PORT)).collect(Collectors.toList()); bootstrapNodes = rawBootstrapNodes.stream()
.map(e -> e.withP2pIdAndPort(Node.TEST_NET_P2P_ID, Node.TEST_NET_PORT)).collect(Collectors.toList());
localhostNode = rawLocalhostNode.withP2pIdAndPort(Node.TEST_NET_P2P_ID, Node.TEST_NET_PORT);
break;
case Node.REG_TEST_P2P_ID: case Node.REG_TEST_P2P_ID:
return bootstrapNodes.stream().map(e -> e.withP2pIdAndPort(Node.REG_TEST_P2P_ID, Node.REG_TEST_PORT)).collect(Collectors.toList()); bootstrapNodes = rawBootstrapNodes.stream()
.map(e -> e.withP2pIdAndPort(Node.REG_TEST_P2P_ID, Node.REG_TEST_PORT)).collect(Collectors.toList());
localhostNode = rawLocalhostNode.withP2pIdAndPort(Node.REG_TEST_P2P_ID, Node.REG_TEST_PORT);
break;
default: default:
throw new BitsquareException("Unsupported P2pId. p2pId=" + p2pId); throw new BitsquareException("Unsupported P2pId. p2pId=" + p2pId);
} }
} }
}
public static Node selectNode(int p2pId) { else {
if (selectedNode == null) throw new BitsquareException("initWithNetworkId called twice");
selectedNode = getAllBootstrapNodes(p2pId).get(new Random().nextInt(bootstrapNodes.size())); }
else
throw new BitsquareException("selectNode must be called only once.");
return selectedNode;
} }
public static Node getSelectedNode() { public Node getRandomDiscoverNode() {
if (selectedNode == null) return bootstrapNodes.get(new Random().nextInt(rawBootstrapNodes.size()));
throw new BitsquareException("selectNode must be called first.");
return selectedNode;
} }
public static Node getFallbackNode() { public List<Node> getBootstrapNodes() {
if (bootstrapNodes.size() > 1) return bootstrapNodes;
return BootstrapNodes.getAllBootstrapNodes(selectedNode.getP2pId()).stream().filter(e -> !e.equals(selectedNode)).findAny().get(); }
else
public List<PeerAddress> getBootstrapPeerAddresses() {
return bootstrapNodes.stream().map(e -> {
try {
return new PeerAddress(Number160.createHash(e.getName()), InetAddress.getByName(e.getIp()), e.getPort(), e.getPort());
} catch (UnknownHostException e1) {
e1.printStackTrace();
log.error(e1.getMessage());
return null; return null;
}
}).collect(Collectors.toList());
} }
// Localhost default use regtest public Node getLocalhostNode() {
private static Node localhostNode = selectLocalhostNode(Node.REG_TEST_P2P_ID);
public static Node selectLocalhostNode(int p2pId) {
final Node localhostNode = Node.at("localhost", "127.0.0.1");
switch (p2pId) {
case Node.MAIN_NET_P2P_ID:
BootstrapNodes.localhostNode = localhostNode.withP2pIdAndPort(Node.MAIN_NET_P2P_ID, Node.MAIN_NET_PORT);
break;
case Node.TEST_NET_P2P_ID:
BootstrapNodes.localhostNode = localhostNode.withP2pIdAndPort(Node.TEST_NET_P2P_ID, Node.TEST_NET_PORT);
break;
case Node.REG_TEST_P2P_ID:
BootstrapNodes.localhostNode = localhostNode.withP2pIdAndPort(Node.REG_TEST_P2P_ID, Node.REG_TEST_PORT);
break;
default:
throw new BitsquareException("Unsupported P2pId. p2pId=" + p2pId);
}
return BootstrapNodes.localhostNode;
}
public static Node getLocalhostNode() {
return localhostNode; return localhostNode;
} }
public int getP2pId() {
return p2pId;
}
} }

View file

@ -32,9 +32,7 @@ public interface ClientNode {
String getClientNodeInfo(); String getClientNodeInfo();
Node getBootstrapNode(); Observable<BootstrappedPeerBuilder.State> bootstrap(KeyPair keyPair);
Observable<BootstrappedPeerBuilder.State> bootstrap(int networkId, KeyPair keyPair);
ReadOnlyIntegerProperty numPeersProperty(); ReadOnlyIntegerProperty numPeersProperty();

View file

@ -64,7 +64,7 @@ public final class Node {
} }
// Not fully defined node // Not fully defined node
public static Node at(String name, String ip) { public static Node rawNodeAt(String name, String ip) {
return Node.at(name, ip, -1, -1); return Node.at(name, ip, -1, -1);
} }
@ -76,10 +76,6 @@ public final class Node {
return Node.at(this.name, this.ip, p2pId, port); return Node.at(this.name, this.ip, p2pId, port);
} }
/* public static Node at(String name, int p2pId, String ip) {
return Node.at(name, ip, p2pId, DEFAULT_PORT);
}*/
public static final int CLIENT_PORT = findFreeSystemPort(); public static final int CLIENT_PORT = findFreeSystemPort();
public static int findFreeSystemPort() { public static int findFreeSystemPort() {
@ -98,8 +94,20 @@ public final class Node {
public PeerAddress toPeerAddressWithPort(int port) { public PeerAddress toPeerAddressWithPort(int port) {
try { try {
return new PeerAddress(Number160.createHash(getName()), return new PeerAddress(Number160.createHash(name),
InetAddress.getByName(getIp()), InetAddress.getByName(ip),
port,
port);
} catch (UnknownHostException e) {
log.error(e.getMessage());
throw new RuntimeException(e);
}
}
public PeerAddress toPeerAddress() {
try {
return new PeerAddress(Number160.createHash(name),
InetAddress.getByName(ip),
port, port,
port); port);
} catch (UnknownHostException e) { } catch (UnknownHostException e) {

View file

@ -27,9 +27,6 @@ import com.google.inject.name.Named;
import java.io.IOException; import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.security.KeyPair; import java.security.KeyPair;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
@ -55,7 +52,6 @@ import net.tomp2p.nat.PeerBuilderNAT;
import net.tomp2p.nat.PeerNAT; import net.tomp2p.nat.PeerNAT;
import net.tomp2p.p2p.Peer; import net.tomp2p.p2p.Peer;
import net.tomp2p.p2p.PeerBuilder; import net.tomp2p.p2p.PeerBuilder;
import net.tomp2p.peers.Number160;
import net.tomp2p.peers.PeerAddress; import net.tomp2p.peers.PeerAddress;
import net.tomp2p.peers.PeerMapChangeListener; import net.tomp2p.peers.PeerMapChangeListener;
import net.tomp2p.peers.PeerStatistic; import net.tomp2p.peers.PeerStatistic;
@ -75,7 +71,6 @@ import io.netty.util.concurrent.DefaultEventExecutorGroup;
public class BootstrappedPeerBuilder { public class BootstrappedPeerBuilder {
private static final Logger log = LoggerFactory.getLogger(BootstrappedPeerBuilder.class); private static final Logger log = LoggerFactory.getLogger(BootstrappedPeerBuilder.class);
static final String BOOTSTRAP_NODE_KEY = "bootstrapNode";
static final String NETWORK_INTERFACE_KEY = "interface"; static final String NETWORK_INTERFACE_KEY = "interface";
static final String NETWORK_INTERFACE_UNSPECIFIED = "<unspecified>"; static final String NETWORK_INTERFACE_UNSPECIFIED = "<unspecified>";
static final String USE_MANUAL_PORT_FORWARDING_KEY = "node.useManualPortForwarding"; static final String USE_MANUAL_PORT_FORWARDING_KEY = "node.useManualPortForwarding";
@ -117,17 +112,16 @@ public class BootstrappedPeerBuilder {
private final int port; private final int port;
private final boolean useManualPortForwarding; private final boolean useManualPortForwarding;
private final String networkInterface; private final String networkInterface;
private BootstrapNodes bootstrapNodes;
private final Preferences preferences; 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 KeyPair keyPair;
private Peer peer; private Peer peer;
private PeerDHT peerDHT; private PeerDHT peerDHT;
private boolean retriedOtherBootstrapNode;
private Executor executor; private Executor executor;
@ -138,13 +132,13 @@ public class BootstrappedPeerBuilder {
@Inject @Inject
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(NETWORK_INTERFACE_KEY) String networkInterface, @Named(NETWORK_INTERFACE_KEY) String networkInterface,
BootstrapNodes bootstrapNodes,
Preferences preferences) { Preferences preferences) {
this.port = port; this.port = port;
this.useManualPortForwarding = useManualPortForwarding; this.useManualPortForwarding = useManualPortForwarding;
this.bootstrapNode = bootstrapNode;
this.networkInterface = networkInterface; this.networkInterface = networkInterface;
this.bootstrapNodes = bootstrapNodes;
this.preferences = preferences; this.preferences = preferences;
} }
@ -166,28 +160,8 @@ public class BootstrappedPeerBuilder {
this.executor = executor; this.executor = executor;
} }
public SettableFuture<PeerDHT> start(int p2pId) { public SettableFuture<PeerDHT> start() {
try { try {
Node selectedNode = BootstrapNodes.selectNode(p2pId);
String bootstrapNodeName = bootstrapNode.getName();
if (bootstrapNodeName == null)
bootstrapNodeName = selectedNode.getName();
String bootstrapNodeIp = bootstrapNode.getIp();
if (bootstrapNodeIp == null)
bootstrapNodeIp = selectedNode.getIp();
int bootstrapNodeP2pId = bootstrapNode.getP2pId();
if (bootstrapNodeP2pId == -1)
bootstrapNodeP2pId = selectedNode.getP2pId();
int bootstrapNodePort = bootstrapNode.getPort();
if (bootstrapNodePort == -1)
bootstrapNodePort = selectedNode.getPort();
bootstrapNode = Node.at(bootstrapNodeName, bootstrapNodeIp, bootstrapNodeP2pId, bootstrapNodePort);
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));
@ -202,7 +176,7 @@ public class BootstrappedPeerBuilder {
if (useManualPortForwarding) { if (useManualPortForwarding) {
peer = new PeerBuilder(keyPair) peer = new PeerBuilder(keyPair)
.p2pId(p2pId) .p2pId(bootstrapNodes.getP2pId())
.channelClientConfiguration(clientConf) .channelClientConfiguration(clientConf)
.channelServerConfiguration(serverConf) .channelServerConfiguration(serverConf)
.ports(port) .ports(port)
@ -213,7 +187,7 @@ public class BootstrappedPeerBuilder {
} }
else { else {
peer = new PeerBuilder(keyPair) peer = new PeerBuilder(keyPair)
.p2pId(p2pId) .p2pId(bootstrapNodes.getP2pId())
.channelClientConfiguration(clientConf) .channelClientConfiguration(clientConf)
.channelServerConfiguration(serverConf) .channelServerConfiguration(serverConf)
.ports(port) .ports(port)
@ -270,13 +244,13 @@ public class BootstrappedPeerBuilder {
// bootstrap node and use that peer as relay // bootstrap node and use that peer as relay
private void discoverExternalAddressUsingUPnP() { private void discoverExternalAddressUsingUPnP() {
FutureDiscover futureDiscover = peer.discover().peerAddress(getBootstrapAddress()).start(); Node randomNode = bootstrapNodes.getRandomDiscoverNode();
log.info("Random Node for discovering own address visible form outside: " + randomNode);
FutureDiscover futureDiscover = peer.discover().peerAddress(randomNode.toPeerAddress()).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);
futureRelayNAT.addListener(new BaseFutureListener<BaseFuture>() { futureRelayNAT.addListener(new BaseFutureListener<BaseFuture>() {
@Override @Override
public void operationComplete(BaseFuture futureRelayNAT) throws Exception { public void operationComplete(BaseFuture futureRelayNAT) throws Exception {
@ -308,14 +282,6 @@ public class BootstrappedPeerBuilder {
setConnectionType(ConnectionType.RELAY); setConnectionType(ConnectionType.RELAY);
bootstrap(); bootstrap();
} }
else {
Node fallbackNode = BootstrapNodes.getFallbackNode();
if (!retriedOtherBootstrapNode && fallbackNode != null) {
retriedOtherBootstrapNode = true;
bootstrapNode = fallbackNode;
log.warn("Bootstrap failed with bootstrapNode: " + bootstrapNode + ". We try again with another node.");
executor.execute(() -> discoverExternalAddress());
}
else { else {
// All attempts failed. Give up... // All attempts failed. Give up...
handleError(State.RELAY_FAILED, "NAT traversal using relay mode failed " + futureRelayNAT.failedReason()); handleError(State.RELAY_FAILED, "NAT traversal using relay mode failed " + futureRelayNAT.failedReason());
@ -323,7 +289,6 @@ public class BootstrappedPeerBuilder {
} }
} }
} }
}
@Override @Override
public void exceptionCaught(Throwable t) throws Exception { public void exceptionCaught(Throwable t) throws Exception {
@ -333,12 +298,12 @@ public class BootstrappedPeerBuilder {
} }
private void discoverExternalAddress() { private void discoverExternalAddress() {
FutureDiscover futureDiscover = peer.discover().peerAddress(getBootstrapAddress()).start(); Node randomNode = bootstrapNodes.getRandomDiscoverNode();
log.info("Random Node for discovering own address visible form outside: " + randomNode);
FutureDiscover futureDiscover = peer.discover().peerAddress(randomNode.toPeerAddress()).start();
setState(State.DISCOVERY_STARTED); setState(State.DISCOVERY_STARTED);
PeerNAT peerNAT = new PeerBuilderNAT(peer).start(); PeerNAT peerNAT = new PeerBuilderNAT(peer).start();
FutureRelayNAT futureRelayNAT = peerNAT.startRelay(new TCPRelayClientConfig(), futureDiscover); FutureRelayNAT futureRelayNAT = peerNAT.startRelay(new TCPRelayClientConfig(), futureDiscover);
futureRelayNAT.addListener(new BaseFutureListener<BaseFuture>() { futureRelayNAT.addListener(new BaseFutureListener<BaseFuture>() {
@Override @Override
public void operationComplete(BaseFuture futureRelayNAT) throws Exception { public void operationComplete(BaseFuture futureRelayNAT) throws Exception {
@ -362,21 +327,12 @@ public class BootstrappedPeerBuilder {
setConnectionType(ConnectionType.RELAY); setConnectionType(ConnectionType.RELAY);
bootstrap(); bootstrap();
} }
else {
Node fallbackNode = BootstrapNodes.getFallbackNode();
if (!retriedOtherBootstrapNode && fallbackNode != null) {
retriedOtherBootstrapNode = true;
bootstrapNode = fallbackNode;
log.warn("Bootstrap failed with bootstrapNode: " + bootstrapNode + ". We try again with another node.");
executor.execute(() -> discoverExternalAddress());
}
else { else {
// All attempts failed. Give up... // All attempts failed. Give up...
handleError(State.RELAY_FAILED, "NAT traversal using relay mode failed " + futureRelayNAT.failedReason()); handleError(State.RELAY_FAILED, "NAT traversal using relay mode failed " + futureRelayNAT.failedReason());
} }
} }
} }
}
@Override @Override
public void exceptionCaught(Throwable t) throws Exception { public void exceptionCaught(Throwable t) throws Exception {
@ -389,9 +345,7 @@ public class BootstrappedPeerBuilder {
log.trace("start bootstrap"); log.trace("start bootstrap");
// We don't wait until bootstrap is done for speeding up startup process // We don't wait until bootstrap is done for speeding up startup process
// settableFuture.set(peerDHT); FutureBootstrap futureBootstrap = peer.bootstrap().bootstrapTo(bootstrapNodes.getBootstrapPeerAddresses()).start();
FutureBootstrap futureBootstrap = peer.bootstrap().peerAddress(getBootstrapAddress()).start();
futureBootstrap.addListener(new BaseFutureListener<BaseFuture>() { futureBootstrap.addListener(new BaseFutureListener<BaseFuture>() {
@Override @Override
public void operationComplete(BaseFuture future) throws Exception { public void operationComplete(BaseFuture future) throws Exception {
@ -413,22 +367,6 @@ public class BootstrappedPeerBuilder {
}); });
} }
private PeerAddress getBootstrapAddress() {
try {
return new PeerAddress(Number160.createHash(bootstrapNode.getName()),
InetAddress.getByName(bootstrapNode.getIp()),
bootstrapNode.getPort(),
bootstrapNode.getPort());
} catch (UnknownHostException e) {
log.error("getBootstrapAddress failed: " + e.getMessage());
return null;
}
}
public Node getBootstrapNode() {
return bootstrapNode;
}
public ConnectionType getConnectionType() { public ConnectionType getConnectionType() {
return connectionType.get(); return connectionType.get();
} }

View file

@ -18,6 +18,7 @@
package io.bitsquare.p2p.tomp2p; package io.bitsquare.p2p.tomp2p;
import io.bitsquare.p2p.AddressService; import io.bitsquare.p2p.AddressService;
import io.bitsquare.p2p.BootstrapNodes;
import io.bitsquare.p2p.ClientNode; import io.bitsquare.p2p.ClientNode;
import io.bitsquare.p2p.MailboxService; import io.bitsquare.p2p.MailboxService;
import io.bitsquare.p2p.MessageService; import io.bitsquare.p2p.MessageService;
@ -33,7 +34,7 @@ import org.slf4j.LoggerFactory;
import org.springframework.core.env.Environment; import org.springframework.core.env.Environment;
import static io.bitsquare.p2p.tomp2p.BootstrappedPeerBuilder.*; import static io.bitsquare.p2p.tomp2p.BootstrappedPeerBuilder.NETWORK_INTERFACE_UNSPECIFIED;
public class TomP2PModule extends P2PModule { public class TomP2PModule extends P2PModule {
private static final Logger log = LoggerFactory.getLogger(TomP2PModule.class); private static final Logger log = LoggerFactory.getLogger(TomP2PModule.class);
@ -51,6 +52,7 @@ public class TomP2PModule extends P2PModule {
@Override @Override
protected void doConfigure() { protected void doConfigure() {
// Used both ClientNode and TomP2PNode for injection // Used both ClientNode and TomP2PNode for injection
bind(BootstrapNodes.class).in(Singleton.class);
bind(ClientNode.class).to(TomP2PNode.class).in(Singleton.class); bind(ClientNode.class).to(TomP2PNode.class).in(Singleton.class);
bind(TomP2PNode.class).in(Singleton.class); bind(TomP2PNode.class).in(Singleton.class);
@ -64,7 +66,7 @@ public class TomP2PModule extends P2PModule {
bind(boolean.class).annotatedWith(Names.named(USE_MANUAL_PORT_FORWARDING_KEY)).toInstance( bind(boolean.class).annotatedWith(Names.named(USE_MANUAL_PORT_FORWARDING_KEY)).toInstance(
env.getProperty(USE_MANUAL_PORT_FORWARDING_KEY, boolean.class, false)); env.getProperty(USE_MANUAL_PORT_FORWARDING_KEY, boolean.class, false));
bind(Node.class).annotatedWith(Names.named(BOOTSTRAP_NODE_KEY)).toInstance( bind(Node.class).annotatedWith(Names.named(BootstrapNodes.BOOTSTRAP_NODE_KEY)).toInstance(
Node.at(env.getProperty(BOOTSTRAP_NODE_NAME_KEY, ""), Node.at(env.getProperty(BOOTSTRAP_NODE_NAME_KEY, ""),
env.getProperty(BOOTSTRAP_NODE_IP_KEY, ""), env.getProperty(BOOTSTRAP_NODE_IP_KEY, ""),
Integer.valueOf(env.getProperty(BOOTSTRAP_NODE_P2P_ID_KEY, "-1")), Integer.valueOf(env.getProperty(BOOTSTRAP_NODE_P2P_ID_KEY, "-1")),

View file

@ -21,7 +21,6 @@ import io.bitsquare.BitsquareException;
import io.bitsquare.common.handlers.ResultHandler; import io.bitsquare.common.handlers.ResultHandler;
import io.bitsquare.p2p.BaseP2PService; import io.bitsquare.p2p.BaseP2PService;
import io.bitsquare.p2p.ClientNode; import io.bitsquare.p2p.ClientNode;
import io.bitsquare.p2p.Node;
import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.Futures;
@ -91,7 +90,7 @@ public class TomP2PNode implements ClientNode {
bootstrappedPeerBuilder.setExecutor(executor); bootstrappedPeerBuilder.setExecutor(executor);
} }
public Observable<BootstrappedPeerBuilder.State> bootstrap(int p2pId, KeyPair keyPair) { public Observable<BootstrappedPeerBuilder.State> bootstrap(KeyPair keyPair) {
bootstrappedPeerBuilder.setKeyPair(keyPair); bootstrappedPeerBuilder.setKeyPair(keyPair);
bootstrappedPeerBuilder.getState().addListener((ov, oldValue, newValue) -> { bootstrappedPeerBuilder.getState().addListener((ov, oldValue, newValue) -> {
@ -99,7 +98,7 @@ public class TomP2PNode implements ClientNode {
bootstrapStateSubject.onNext(newValue); bootstrapStateSubject.onNext(newValue);
}); });
SettableFuture<PeerDHT> bootstrapFuture = bootstrappedPeerBuilder.start(p2pId); SettableFuture<PeerDHT> bootstrapFuture = bootstrappedPeerBuilder.start();
Futures.addCallback(bootstrapFuture, new FutureCallback<PeerDHT>() { Futures.addCallback(bootstrapFuture, new FutureCallback<PeerDHT>() {
@Override @Override
public void onSuccess(@Nullable PeerDHT peerDHT) { public void onSuccess(@Nullable PeerDHT peerDHT) {
@ -179,11 +178,6 @@ public class TomP2PNode implements ClientNode {
"; port=" + peerAddress.peerSocketAddress().tcpPort(); "; port=" + peerAddress.peerSocketAddress().tcpPort();
} }
@Override
public Node getBootstrapNode() {
return bootstrappedPeerBuilder.getBootstrapNode();
}
public void addResultHandler(ResultHandler resultHandler) { public void addResultHandler(ResultHandler resultHandler) {
resultHandlers.add(resultHandler); resultHandlers.add(resultHandler);
} }

View file

@ -47,12 +47,10 @@ public class BuyerAsOffererTrade extends BuyerTrade implements OffererTrade, Ser
public BuyerAsOffererTrade(Offer offer, Storage<? extends TradableList> storage) { public BuyerAsOffererTrade(Offer offer, Storage<? extends TradableList> storage) {
super(offer, storage); super(offer, storage);
log.trace("Created by constructor");
} }
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
in.defaultReadObject(); in.defaultReadObject();
log.trace("Created from serialized form.");
initStateProperties(); initStateProperties();
initAmountProperty(); initAmountProperty();

View file

@ -46,12 +46,10 @@ public class BuyerAsTakerTrade extends BuyerTrade implements TakerTrade, Seriali
public BuyerAsTakerTrade(Offer offer, Coin tradeAmount, Peer tradingPeer, Storage<? extends TradableList> storage) { public BuyerAsTakerTrade(Offer offer, Coin tradeAmount, Peer tradingPeer, Storage<? extends TradableList> storage) {
super(offer, tradeAmount, tradingPeer, storage); super(offer, tradeAmount, tradingPeer, storage);
log.trace("Created by constructor");
} }
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
in.defaultReadObject(); in.defaultReadObject();
log.trace("Created from serialized form.");
initStateProperties(); initStateProperties();
initAmountProperty(); initAmountProperty();

View file

@ -40,12 +40,10 @@ public abstract class BuyerTrade extends Trade implements Serializable {
public BuyerTrade(Offer offer, Coin tradeAmount, Peer tradingPeer, Storage<? extends TradableList> storage) { public BuyerTrade(Offer offer, Coin tradeAmount, Peer tradingPeer, Storage<? extends TradableList> storage) {
super(offer, tradeAmount, tradingPeer, storage); super(offer, tradeAmount, tradingPeer, storage);
log.trace("Created by constructor");
} }
public BuyerTrade(Offer offer, Storage<? extends TradableList> storage) { public BuyerTrade(Offer offer, Storage<? extends TradableList> storage) {
super(offer, storage); super(offer, storage);
log.trace("Created by constructor");
} }
@Override @Override

View file

@ -45,12 +45,10 @@ public class SellerAsOffererTrade extends SellerTrade implements OffererTrade, S
public SellerAsOffererTrade(Offer offer, Storage<? extends TradableList> storage) { public SellerAsOffererTrade(Offer offer, Storage<? extends TradableList> storage) {
super(offer, storage); super(offer, storage);
log.trace("Created by constructor");
} }
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
in.defaultReadObject(); in.defaultReadObject();
log.trace("Created from serialized form.");
initStateProperties(); initStateProperties();
initAmountProperty(); initAmountProperty();

View file

@ -45,12 +45,10 @@ public class SellerAsTakerTrade extends SellerTrade implements TakerTrade, Seria
public SellerAsTakerTrade(Offer offer, Coin tradeAmount, Peer tradingPeer, Storage<? extends TradableList> storage) { public SellerAsTakerTrade(Offer offer, Coin tradeAmount, Peer tradingPeer, Storage<? extends TradableList> storage) {
super(offer, tradeAmount, tradingPeer, storage); super(offer, tradeAmount, tradingPeer, storage);
log.trace("Created by constructor");
} }
private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException { private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException {
in.defaultReadObject(); in.defaultReadObject();
log.trace("Created from serialized form.");
initStateProperties(); initStateProperties();
initAmountProperty(); initAmountProperty();

View file

@ -40,12 +40,10 @@ public abstract class SellerTrade extends Trade implements Serializable {
public SellerTrade(Offer offer, Coin tradeAmount, Peer tradingPeer, Storage<? extends TradableList> storage) { public SellerTrade(Offer offer, Coin tradeAmount, Peer tradingPeer, Storage<? extends TradableList> storage) {
super(offer, tradeAmount, tradingPeer, storage); super(offer, tradeAmount, tradingPeer, storage);
log.trace("Created by constructor");
} }
public SellerTrade(Offer offer, Storage<? extends TradableList> storage) { public SellerTrade(Offer offer, Storage<? extends TradableList> storage) {
super(offer, storage); super(offer, storage);
log.trace("Created by constructor");
} }
@Override @Override

View file

@ -49,8 +49,6 @@ public class TradableList<T extends Tradable> extends ArrayList<T> implements Se
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
public TradableList(Storage<TradableList<T>> storage, String fileName) { public TradableList(Storage<TradableList<T>> storage, String fileName) {
log.trace("Created by constructor");
this.storage = storage; this.storage = storage;
TradableList persisted = storage.initAndGetPersisted(this, fileName); TradableList persisted = storage.initAndGetPersisted(this, fileName);
@ -62,7 +60,6 @@ public class TradableList<T extends Tradable> extends ArrayList<T> implements Se
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
in.defaultReadObject(); in.defaultReadObject();
log.trace("Created from serialized form.");
} }
@Override @Override

View file

@ -128,7 +128,6 @@ abstract public class Trade implements Tradable, Model, Serializable {
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
protected Trade(Offer offer, Storage<? extends TradableList> storage) { protected Trade(Offer offer, Storage<? extends TradableList> storage) {
log.trace("Created by constructor");
this.offer = offer; this.offer = offer;
this.storage = storage; this.storage = storage;
@ -156,7 +155,6 @@ abstract public class Trade implements Tradable, Model, Serializable {
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
in.defaultReadObject(); in.defaultReadObject();
log.trace("Created from serialized form.");
initStateProperties(); initStateProperties();
initAmountProperty(); initAmountProperty();

View file

@ -80,13 +80,11 @@ public class ProcessModel implements Model, Serializable {
public ProcessModel() { public ProcessModel() {
log.trace("Created by constructor");
tradingPeer = new TradingPeer(); tradingPeer = new TradingPeer();
} }
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
in.defaultReadObject(); in.defaultReadObject();
log.trace("Created from serialized form.");
} }
public void onAllServicesInitialized(Offer offer, public void onAllServicesInitialized(Offer offer,

View file

@ -60,12 +60,10 @@ public class TradingPeer implements Serializable {
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
public TradingPeer() { public TradingPeer() {
log.trace("Created by constructor");
} }
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
in.defaultReadObject(); in.defaultReadObject();
log.trace("Created from serialized form.");
} }

View file

@ -17,6 +17,7 @@
package io.bitsquare.user; package io.bitsquare.user;
import io.bitsquare.app.BitsquareEnvironment;
import io.bitsquare.app.Version; import io.bitsquare.app.Version;
import io.bitsquare.btc.BitcoinNetwork; import io.bitsquare.btc.BitcoinNetwork;
import io.bitsquare.storage.Storage; import io.bitsquare.storage.Storage;
@ -38,8 +39,6 @@ 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;
@ -48,11 +47,13 @@ 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;
} }
transient private final Storage<Preferences> storage; transient private final Storage<Preferences> storage;
transient private BitsquareEnvironment bitsquareEnvironment;
// Persisted fields // Persisted fields
private String btcDenomination = MonetaryFormat.CODE_BTC; private String btcDenomination = MonetaryFormat.CODE_BTC;
@ -61,7 +62,7 @@ public class Preferences implements Serializable {
private boolean useEffects = true; private boolean useEffects = true;
private boolean displaySecurityDepositInfo = true; private boolean displaySecurityDepositInfo = true;
private boolean useUPnP = true; private boolean useUPnP = true;
private BitcoinNetwork bitcoinNetwork; transient private BitcoinNetwork bitcoinNetwork;
// Observable wrappers // Observable wrappers
transient private final StringProperty btcDenominationProperty = new SimpleStringProperty(btcDenomination); transient private final StringProperty btcDenominationProperty = new SimpleStringProperty(btcDenomination);
@ -74,8 +75,9 @@ public class Preferences implements Serializable {
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
@Inject @Inject
public Preferences(Storage<Preferences> storage, Environment environment) { public Preferences(Storage<Preferences> storage, BitsquareEnvironment bitsquareEnvironment) {
this.storage = storage; this.storage = storage;
this.bitsquareEnvironment = bitsquareEnvironment;
Preferences persisted = storage.initAndGetPersisted(this); Preferences persisted = storage.initAndGetPersisted(this);
if (persisted != null) { if (persisted != null) {
@ -83,12 +85,10 @@ public class Preferences implements Serializable {
setUseAnimations(persisted.useAnimations); setUseAnimations(persisted.useAnimations);
setUseEffects(persisted.useEffects); setUseEffects(persisted.useEffects);
setUseUPnP(persisted.useUPnP); setUseUPnP(persisted.useUPnP);
setBitcoinNetwork(persisted.bitcoinNetwork);
displaySecurityDepositInfo = persisted.getDisplaySecurityDepositInfo(); displaySecurityDepositInfo = persisted.getDisplaySecurityDepositInfo();
} }
else {
setBitcoinNetwork(environment.getProperty(BitcoinNetwork.KEY, BitcoinNetwork.class, BitcoinNetwork.DEFAULT)); setBitcoinNetwork(bitsquareEnvironment.getBtcNetworkProperty());
}
// 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) -> {
@ -133,8 +133,10 @@ public class Preferences implements Serializable {
} }
public void setBitcoinNetwork(BitcoinNetwork bitcoinNetwork) { public void setBitcoinNetwork(BitcoinNetwork bitcoinNetwork) {
if (this.bitcoinNetwork != bitcoinNetwork)
bitsquareEnvironment.setBitcoinNetwork(bitcoinNetwork);
this.bitcoinNetwork = bitcoinNetwork; this.bitcoinNetwork = bitcoinNetwork;
storage.queueUpForSave();
} }

View file

@ -26,8 +26,8 @@ public class NodeTests {
@Test @Test
public void testEqualsAndHashCode() { public void testEqualsAndHashCode() {
Node node1a = Node.at("bitsquare1.example.com", "203.0.113.1"); Node node1a = Node.rawNodeAt("bitsquare1.example.com", "203.0.113.1");
Node node1b = Node.at("bitsquare1.example.com", "203.0.113.1"); Node node1b = Node.rawNodeAt("bitsquare1.example.com", "203.0.113.1");
assertThat(node1a, equalTo(node1a)); assertThat(node1a, equalTo(node1a));
@ -37,10 +37,10 @@ public class NodeTests {
assertThat(node1a, not((Object) equalTo(null))); assertThat(node1a, not((Object) equalTo(null)));
assertThat(node1a, not((Object) equalTo("not a node"))); assertThat(node1a, not((Object) equalTo("not a node")));
assertThat(node1a, not(equalTo(Node.at("bitsquare2.example.com", node1a.getIp())))); assertThat(node1a, not(equalTo(Node.rawNodeAt("bitsquare2.example.com", node1a.getIp()))));
assertThat(node1a, not(equalTo(Node.at(node1a.getName(), "203.0.113.2")))); assertThat(node1a, not(equalTo(Node.rawNodeAt(node1a.getName(), "203.0.113.2"))));
Node node2 = Node.at("bitsquare2.example.com", "203.0.113.2"); Node node2 = Node.rawNodeAt("bitsquare2.example.com", "203.0.113.2");
assertThat(node1a.hashCode(), equalTo(node1b.hashCode())); assertThat(node1a.hashCode(), equalTo(node1b.hashCode()));
assertThat(node1a.hashCode(), not(equalTo(node2.hashCode()))); assertThat(node1a.hashCode(), not(equalTo(node2.hashCode())));
} }

View file

@ -90,11 +90,14 @@ public class TomP2PTests {
private static final PeerAddress BOOTSTRAP_NODE_ADDRESS; private static final PeerAddress BOOTSTRAP_NODE_ADDRESS;
private static final BootstrapNodes bootstrapNodes;
static { static {
int p2pId = 1; int p2pId = 1;
bootstrapNodes = new BootstrapNodes();
if (FORCED_CONNECTION_TYPE == BootstrappedPeerBuilder.ConnectionType.DIRECT) { if (FORCED_CONNECTION_TYPE == BootstrappedPeerBuilder.ConnectionType.DIRECT) {
BootstrapNodes.selectLocalhostNode(p2pId); bootstrapNodes.initWithNetworkId(p2pId);
BOOTSTRAP_NODE = BootstrapNodes.getLocalhostNode(); BOOTSTRAP_NODE = bootstrapNodes.getLocalhostNode();
} }
else { else {
BOOTSTRAP_NODE = Node.at("digitalocean1.dev.bitsquare.io", "188.226.179.109", p2pId, 7367); BOOTSTRAP_NODE = Node.at("digitalocean1.dev.bitsquare.io", "188.226.179.109", p2pId, 7367);
@ -318,9 +321,7 @@ public class TomP2PTests {
PeerDHT peer1 = new PeerBuilderDHT(new PeerBuilder(Number160.createHash("peer1")).ports(3006).start()).start(); PeerDHT peer1 = new PeerBuilderDHT(new PeerBuilder(Number160.createHash("peer1")).ports(3006).start()).start();
PeerDHT peer2 = new PeerBuilderDHT(new PeerBuilder(Number160.createHash("peer2")).ports(3007).start()).start(); PeerDHT peer2 = new PeerBuilderDHT(new PeerBuilder(Number160.createHash("peer2")).ports(3007).start()).start();
*/ */
PeerAddress masterPeerAddress = new PeerAddress(Number160.createHash(BootstrapNodes.getLocalhostNode().getName()), PeerAddress masterPeerAddress = bootstrapNodes.getLocalhostNode().toPeerAddress();
BootstrapNodes.getLocalhostNode().getIp(), BootstrapNodes.getLocalhostNode().getPort(),
BootstrapNodes.getLocalhostNode().getPort());
// start both at the same time // start both at the same time
BaseFuture fb1 = peer1.peer().bootstrap().peerAddress(masterPeerAddress).start(); BaseFuture fb1 = peer1.peer().bootstrap().peerAddress(masterPeerAddress).start();

View file

@ -123,7 +123,7 @@ public class BitsquareAppMain extends BitsquareExecutable {
parser.accepts(USE_MANUAL_PORT_FORWARDING_KEY, description("Use manual port forwarding", false)) parser.accepts(USE_MANUAL_PORT_FORWARDING_KEY, description("Use manual port forwarding", false))
.withRequiredArg() .withRequiredArg()
.ofType(boolean.class); .ofType(boolean.class);
parser.accepts(BitcoinNetwork.KEY, description("", BitcoinNetwork.DEFAULT)) parser.accepts(BitcoinNetwork.KEY, description("Bitcoin network", BitcoinNetwork.DEFAULT))
.withRequiredArg() .withRequiredArg()
.ofType(BitcoinNetwork.class) .ofType(BitcoinNetwork.class)
.withValuesConvertedBy(new EnumValueConverter(BitcoinNetwork.class)); .withValuesConvertedBy(new EnumValueConverter(BitcoinNetwork.class));
@ -133,15 +133,16 @@ public class BitsquareAppMain extends BitsquareExecutable {
.ofType(RegTestHost.class) .ofType(RegTestHost.class)
.withValuesConvertedBy(new EnumValueConverter(RegTestHost.class)); .withValuesConvertedBy(new EnumValueConverter(RegTestHost.class));
BootstrapNodes bootstrapNodes = new BootstrapNodes();
parser.accepts(BOOTSTRAP_NODE_NAME_KEY, description("Bootstrap node name", BootstrapNodes.getLocalhostNode().getName())) bootstrapNodes.initWithNetworkId(Node.REG_TEST_P2P_ID); // use regtest as default
parser.accepts(BOOTSTRAP_NODE_NAME_KEY, description("Bootstrap node name", bootstrapNodes.getLocalhostNode().getName()))
.withRequiredArg(); .withRequiredArg();
parser.accepts(BOOTSTRAP_NODE_IP_KEY, description("Bootstrap node IP", BootstrapNodes.getLocalhostNode().getIp())) parser.accepts(BOOTSTRAP_NODE_IP_KEY, description("Bootstrap node IP", bootstrapNodes.getLocalhostNode().getIp()))
.withRequiredArg(); .withRequiredArg();
parser.accepts(BOOTSTRAP_NODE_P2P_ID_KEY, description("Bootstrap node p2p network ID", BootstrapNodes.getLocalhostNode().getPort())) parser.accepts(BOOTSTRAP_NODE_P2P_ID_KEY, description("Bootstrap node p2p network ID", bootstrapNodes.getLocalhostNode().getPort()))
.withRequiredArg() .withRequiredArg()
.ofType(int.class); .ofType(int.class);
parser.accepts(BOOTSTRAP_NODE_PORT_KEY, description("Bootstrap node port", BootstrapNodes.getLocalhostNode().getPort())) parser.accepts(BOOTSTRAP_NODE_PORT_KEY, description("Bootstrap node port", bootstrapNodes.getLocalhostNode().getPort()))
.withRequiredArg() .withRequiredArg()
.ofType(int.class); .ofType(int.class);
parser.accepts(NETWORK_INTERFACE_KEY, description("Network interface", null)) parser.accepts(NETWORK_INTERFACE_KEY, description("Network interface", null))

View file

@ -73,7 +73,7 @@ class BitsquareAppModule extends BitsquareModule {
File keyStorageDir = new File(env.getRequiredProperty(KeyStorage.DIR_KEY)); File keyStorageDir = new File(env.getRequiredProperty(KeyStorage.DIR_KEY));
bind(File.class).annotatedWith(named(KeyStorage.DIR_KEY)).toInstance(keyStorageDir); bind(File.class).annotatedWith(named(KeyStorage.DIR_KEY)).toInstance(keyStorageDir);
bind(Environment.class).toInstance(env); bind(BitsquareEnvironment.class).toInstance((BitsquareEnvironment) env);
bind(UpdateProcess.class).in(Singleton.class); bind(UpdateProcess.class).in(Singleton.class);
// ordering is used for shut down sequence // ordering is used for shut down sequence

View file

@ -68,7 +68,7 @@ public class UpdateProcess {
protected Timer timeoutTimer; protected Timer timeoutTimer;
@Inject @Inject
public UpdateProcess(Environment environment) { public UpdateProcess(BitsquareEnvironment environment) {
this.environment = environment; this.environment = environment;
} }

View file

@ -27,6 +27,7 @@ import io.bitsquare.gui.common.model.ViewModel;
import io.bitsquare.gui.util.BSFormatter; import io.bitsquare.gui.util.BSFormatter;
import io.bitsquare.locale.CountryUtil; import io.bitsquare.locale.CountryUtil;
import io.bitsquare.p2p.BaseP2PService; import io.bitsquare.p2p.BaseP2PService;
import io.bitsquare.p2p.BootstrapNodes;
import io.bitsquare.p2p.ClientNode; import io.bitsquare.p2p.ClientNode;
import io.bitsquare.p2p.tomp2p.BootstrappedPeerBuilder; import io.bitsquare.p2p.tomp2p.BootstrappedPeerBuilder;
import io.bitsquare.trade.Trade; import io.bitsquare.trade.Trade;
@ -77,7 +78,6 @@ class MainViewModel implements ViewModel {
private final OpenOfferManager openOfferManager; private final OpenOfferManager openOfferManager;
private final UpdateProcess updateProcess; private final UpdateProcess updateProcess;
private final BSFormatter formatter; private final BSFormatter formatter;
private final int p2pId;
// BTC network // BTC network
final StringProperty blockchainSyncInfo = new SimpleStringProperty("Initializing"); final StringProperty blockchainSyncInfo = new SimpleStringProperty("Initializing");
@ -120,7 +120,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, Preferences preferences, UpdateProcess updateProcess, TradeManager tradeManager, OpenOfferManager openOfferManager, Preferences preferences, UpdateProcess updateProcess,
BSFormatter formatter) { BootstrapNodes bootstrapNodes, BSFormatter formatter) {
this.user = user; this.user = user;
this.keyRing = keyRing; this.keyRing = keyRing;
this.walletService = walletService; this.walletService = walletService;
@ -132,7 +132,7 @@ class MainViewModel implements ViewModel {
this.formatter = formatter; this.formatter = formatter;
bitcoinNetworkAsString = formatter.formatBitcoinNetwork(preferences.getBitcoinNetwork()); bitcoinNetworkAsString = formatter.formatBitcoinNetwork(preferences.getBitcoinNetwork());
p2pId = preferences.getBitcoinNetwork().ordinal() + 10; // p2pId: Mainnet 10, testnet 11, regtest 12 bootstrapNodes.initWithNetworkId(preferences.getBitcoinNetwork().ordinal() + 10);
updateProcess.state.addListener((observableValue, oldValue, newValue) -> applyUpdateState(newValue)); updateProcess.state.addListener((observableValue, oldValue, newValue) -> applyUpdateState(newValue));
applyUpdateState(updateProcess.state.get()); applyUpdateState(updateProcess.state.get());
@ -206,7 +206,7 @@ class MainViewModel implements ViewModel {
}); });
clientNode.setExecutor(Platform::runLater); clientNode.setExecutor(Platform::runLater);
Observable<BootstrappedPeerBuilder.State> bootstrapStateAsObservable = clientNode.bootstrap(p2pId, keyRing.getDhtSignatureKeyPair()); Observable<BootstrappedPeerBuilder.State> bootstrapStateAsObservable = clientNode.bootstrap(keyRing.getDhtSignatureKeyPair());
bootstrapStateAsObservable.publish(); bootstrapStateAsObservable.publish();
bootstrapStateAsObservable.subscribe( bootstrapStateAsObservable.subscribe(
state -> Platform.runLater(() -> setBootstrapState(state)), state -> Platform.runLater(() -> setBootstrapState(state)),

View file

@ -85,8 +85,8 @@
<TextField fx:id="nodeAddress" GridPane.rowIndex="6" GridPane.columnIndex="1" <TextField fx:id="nodeAddress" GridPane.rowIndex="6" GridPane.columnIndex="1"
mouseTransparent="true" focusTraversable="false"/> mouseTransparent="true" focusTraversable="false"/>
<Label text="P2P bootstrap node address:" GridPane.rowIndex="7"/> <Label text="P2P bootstrap node addresses:" GridPane.rowIndex="7" GridPane.valignment="TOP"/>
<TextField fx:id="bootstrapNodeAddress" GridPane.rowIndex="7" GridPane.columnIndex="1" <TextArea fx:id="bootstrapNodeAddress" GridPane.rowIndex="7" GridPane.columnIndex="1"
mouseTransparent="true" focusTraversable="false"/> mouseTransparent="true" focusTraversable="false"/>
<columnConstraints> <columnConstraints>

View file

@ -25,11 +25,13 @@ import io.bitsquare.gui.common.view.InitializableView;
import io.bitsquare.gui.components.Popups; 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.locale.BSResources;
import io.bitsquare.p2p.BootstrapNodes;
import io.bitsquare.p2p.ClientNode; import io.bitsquare.p2p.ClientNode;
import io.bitsquare.user.Preferences; import io.bitsquare.user.Preferences;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.stream.Collectors;
import javax.inject.Inject; import javax.inject.Inject;
@ -48,17 +50,20 @@ public class NetworkSettingsView extends InitializableView {
private final String bitcoinNetworkString; private final String bitcoinNetworkString;
private final WalletService walletService; private final WalletService walletService;
private BootstrapNodes bootstrapNodes;
private final Preferences preferences; 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, connectedPeersBTC, connectedPeersP2P;
@FXML CheckBox useUPnP; @FXML CheckBox useUPnP;
@FXML ComboBox<BitcoinNetwork> netWorkComboBox; @FXML ComboBox<BitcoinNetwork> netWorkComboBox;
@FXML TextArea bootstrapNodeAddress;
@Inject @Inject
public NetworkSettingsView(WalletService walletService, ClientNode clientNode, Preferences preferences, BSFormatter public NetworkSettingsView(WalletService walletService, ClientNode clientNode, BootstrapNodes bootstrapNodes, Preferences preferences, BSFormatter
formatter) { formatter) {
this.walletService = walletService; this.walletService = walletService;
this.bootstrapNodes = bootstrapNodes;
this.preferences = preferences; this.preferences = preferences;
this.bitcoinNetworkString = formatter.formatBitcoinNetwork(preferences.getBitcoinNetwork()); this.bitcoinNetworkString = formatter.formatBitcoinNetwork(preferences.getBitcoinNetwork());
this.clientNode = clientNode; this.clientNode = clientNode;
@ -72,7 +77,10 @@ public class NetworkSettingsView extends InitializableView {
connectionType.setText(clientNode.getConnectionType().toString()); connectionType.setText(clientNode.getConnectionType().toString());
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.getClientNodeInfo()); nodeAddress.setText(clientNode.getClientNodeInfo());
bootstrapNodeAddress.setText(clientNode.getBootstrapNode().toString()); String bootstrapNodesText = bootstrapNodes.getBootstrapNodes().stream().map(e -> e.toString() + "\n").collect(Collectors.toList()).toString()
.replace(", ", "").replace("[", "").replace("\n]", "");
bootstrapNodeAddress.setPrefRowCount(bootstrapNodes.getBootstrapNodes().size());
bootstrapNodeAddress.setText(bootstrapNodesText);
useUPnP.setSelected(preferences.getUseUPnP()); useUPnP.setSelected(preferences.getUseUPnP());