diff --git a/core/src/main/java/bisq/core/CoreModule.java b/core/src/main/java/bisq/core/CoreModule.java
index e22d44406ab..65e88eb18dd 100644
--- a/core/src/main/java/bisq/core/CoreModule.java
+++ b/core/src/main/java/bisq/core/CoreModule.java
@@ -30,6 +30,7 @@
import bisq.core.dao.DaoModule;
import bisq.core.filter.FilterModule;
import bisq.core.network.p2p.seed.DefaultSeedNodeRepository;
+import bisq.core.network.p2p.seed.SeedNodeAddressLookup;
import bisq.core.notifications.MobileMessageEncryption;
import bisq.core.notifications.MobileModel;
import bisq.core.notifications.MobileNotificationService;
@@ -98,6 +99,7 @@ protected void configure() {
bind(CorruptedDatabaseFilesHandler.class).in(Singleton.class);
bind(AvoidStandbyModeService.class).in(Singleton.class);
+ bind(SeedNodeAddressLookup.class).in(Singleton.class);
bind(SeedNodeRepository.class).to(DefaultSeedNodeRepository.class).in(Singleton.class);
File storageDir = new File(environment.getRequiredProperty(Storage.STORAGE_DIR));
diff --git a/core/src/main/java/bisq/core/app/BisqEnvironment.java b/core/src/main/java/bisq/core/app/BisqEnvironment.java
index 6f9b1a5f871..9a3ca198c4f 100644
--- a/core/src/main/java/bisq/core/app/BisqEnvironment.java
+++ b/core/src/main/java/bisq/core/app/BisqEnvironment.java
@@ -57,7 +57,6 @@
import java.io.FileOutputStream;
import java.io.IOException;
-import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Properties;
@@ -346,7 +345,7 @@ public BisqEnvironment(PropertySource commandLineProperties) {
bannedPriceRelayNodes = !bannedPriceRelayNodesAsString.isEmpty() ? Arrays.asList(StringUtils.deleteWhitespace(bannedPriceRelayNodesAsString).split(",")) : null;
final String bannedSeedNodesAsString = getProperty(FilterManager.BANNED_SEED_NODES, "");
- bannedSeedNodes = !bannedSeedNodesAsString.isEmpty() ? Arrays.asList(StringUtils.deleteWhitespace(bannedSeedNodesAsString).split(",")) : new ArrayList<>();
+ bannedSeedNodes = !bannedSeedNodesAsString.isEmpty() ? Arrays.asList(StringUtils.deleteWhitespace(bannedSeedNodesAsString).split(",")) : null;
final String bannedBtcNodesAsString = getProperty(FilterManager.BANNED_BTC_NODES, "");
bannedBtcNodes = !bannedBtcNodesAsString.isEmpty() ? Arrays.asList(StringUtils.deleteWhitespace(bannedBtcNodesAsString).split(",")) : null;
diff --git a/core/src/main/java/bisq/core/app/misc/ModuleForAppWithP2p.java b/core/src/main/java/bisq/core/app/misc/ModuleForAppWithP2p.java
index 35413918c2d..16d1c87ea70 100644
--- a/core/src/main/java/bisq/core/app/misc/ModuleForAppWithP2p.java
+++ b/core/src/main/java/bisq/core/app/misc/ModuleForAppWithP2p.java
@@ -26,6 +26,7 @@
import bisq.core.dao.DaoModule;
import bisq.core.filter.FilterModule;
import bisq.core.network.p2p.seed.DefaultSeedNodeRepository;
+import bisq.core.network.p2p.seed.SeedNodeAddressLookup;
import bisq.core.offer.OfferModule;
import bisq.core.proto.network.CoreNetworkProtoResolver;
import bisq.core.proto.persistable.CorePersistenceProtoResolver;
@@ -76,6 +77,7 @@ protected void configure() {
bind(BridgeAddressProvider.class).to(Preferences.class).in(Singleton.class);
bind(TorSetup.class).in(Singleton.class);
+ bind(SeedNodeAddressLookup.class).in(Singleton.class);
bind(SeedNodeRepository.class).to(DefaultSeedNodeRepository.class).in(Singleton.class);
File storageDir = new File(environment.getRequiredProperty(Storage.STORAGE_DIR));
diff --git a/core/src/main/java/bisq/core/network/p2p/seed/DefaultSeedNodeAddresses.java b/core/src/main/java/bisq/core/network/p2p/seed/DefaultSeedNodeAddresses.java
new file mode 100644
index 00000000000..d6ef2f5b5d7
--- /dev/null
+++ b/core/src/main/java/bisq/core/network/p2p/seed/DefaultSeedNodeAddresses.java
@@ -0,0 +1,97 @@
+/*
+ * This file is part of Bisq.
+ *
+ * Bisq is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * Bisq is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with Bisq. If not, see .
+ */
+
+package bisq.core.network.p2p.seed;
+
+import bisq.network.p2p.NodeAddress;
+
+import com.google.common.collect.ImmutableSet;
+
+import java.util.Set;
+
+class DefaultSeedNodeAddresses {
+ // Addresses are used if the last digit of their port match the network id:
+ // - mainnet use port ends in 0
+ // - testnet use port ends in 1
+ // - regtest use port ends in 2
+ public static final Set DEFAULT_LOCALHOST_SEED_NODE_ADDRESSES = ImmutableSet.of(
+ // BTC
+ // mainnet
+ new NodeAddress("localhost:2000"),
+ new NodeAddress("localhost:3000"),
+ new NodeAddress("localhost:4000"),
+
+ // testnet
+ new NodeAddress("localhost:2001"),
+ new NodeAddress("localhost:3001"),
+ new NodeAddress("localhost:4001"),
+
+ // regtest
+ new NodeAddress("localhost:2002"),
+ new NodeAddress("localhost:3002")
+ /* new NodeAddress("localhost:4002"),*/
+ );
+
+ // Addresses are used if their port match the network id:
+ // - mainnet uses port 8000
+ // - testnet uses port 8001
+ // - regtest uses port 8002
+ public static final Set DEFAULT_TOR_SEED_NODE_ADDRESSES = ImmutableSet.of(
+ // BTC mainnet
+ new NodeAddress("5quyxpxheyvzmb2d.onion:8000"), // @miker
+ new NodeAddress("s67qglwhkgkyvr74.onion:8000"), // @emzy
+ new NodeAddress("ef5qnzx6znifo3df.onion:8000"), // @manfredkarrer
+ new NodeAddress("jhgcy2won7xnslrb.onion:8000"), // @manfredkarrer
+ new NodeAddress("3f3cu2yw7u457ztq.onion:8000"), // @manfredkarrer
+ new NodeAddress("723ljisnynbtdohi.onion:8000"), // @manfredkarrer
+ new NodeAddress("rm7b56wbrcczpjvl.onion:8000"), // @manfredkarrer
+ new NodeAddress("fl3mmribyxgrv63c.onion:8000"), // @manfredkarrer
+
+ // local dev
+ // new NodeAddress("joehwtpe7ijnz4df.onion:8000"),
+ // new NodeAddress("uqxi3zrpobhtoes6.onion:8000"),
+
+ // BTC testnet
+ // new NodeAddress("vjkh4ykq7x5skdlt.onion:8001"), // local dev test
+ //new NodeAddress("fjr5w4eckjghqtnu.onion:8001"), // testnet seed 1
+ /* new NodeAddress("74w2sttlo4qk6go3.onion:8001"), // testnet seed 2
+ new NodeAddress("jmc5ajqvtnzqaggm.onion:8001"), // testnet seed 3
+ new NodeAddress("3d56s6acbi3vk52v.onion:8001"), // testnet seed 4*/
+
+ // BTC regtest
+ // For development you need to change that to your local onion addresses
+ // 1. Run a seed node with prog args: --bitcoinNetwork=regtest --nodePort=8002 --myAddress=rxdkppp3vicnbgqt:8002 --appName=bisq_seed_node_rxdkppp3vicnbgqt.onion_8002
+ // 2. Find your local onion address in bisq_seed_node_rxdkppp3vicnbgqt.onion_8002/regtest/tor/hiddenservice/hostname
+ // 3. Shut down the seed node
+ // 4. Rename the directory with your local onion address
+ // 5. Edit here your found onion address (new NodeAddress("YOUR_ONION.onion:8002")
+ new NodeAddress("rxdkppp3vicnbgqt.onion:8002"),
+ new NodeAddress("4ie52dse64kaarxw.onion:8002"),
+
+ // DAO TESTNET (server side regtest dedicated for DAO testing)
+ new NodeAddress("fjr5w4eckjghqtnu.onion:8003"), // testnet seed 1
+ new NodeAddress("74w2sttlo4qk6go3.onion:8003"), // testnet seed 2
+ new NodeAddress("jmc5ajqvtnzqaggm.onion:8003"), // testnet seed 3
+ new NodeAddress("3d56s6acbi3vk52v.onion:8003") // testnet seed 4
+
+ // explorer
+ // new NodeAddress("gtif46mfxirv533z.onion:8003")
+ );
+
+ private DefaultSeedNodeAddresses() {
+ }
+}
diff --git a/core/src/main/java/bisq/core/network/p2p/seed/DefaultSeedNodeRepository.java b/core/src/main/java/bisq/core/network/p2p/seed/DefaultSeedNodeRepository.java
index ad24cb7e30c..6c9e160bebf 100644
--- a/core/src/main/java/bisq/core/network/p2p/seed/DefaultSeedNodeRepository.java
+++ b/core/src/main/java/bisq/core/network/p2p/seed/DefaultSeedNodeRepository.java
@@ -17,87 +17,59 @@
package bisq.core.network.p2p.seed;
-import bisq.core.app.BisqEnvironment;
-
-import bisq.network.NetworkOptionKeys;
import bisq.network.p2p.NodeAddress;
import bisq.network.p2p.seed.SeedNodeRepository;
import javax.inject.Inject;
-import javax.inject.Named;
-
-import java.net.URL;
-
-import java.io.BufferedReader;
-import java.io.FileNotFoundException;
-import java.io.FileReader;
-
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-import java.util.stream.Collectors;
-import javax.annotation.Nullable;
+import java.util.Set;
+import java.util.stream.Stream;
public class DefaultSeedNodeRepository implements SeedNodeRepository {
- private static final Pattern pattern = Pattern.compile("^([a-z0-9]+\\.onion:\\d+)");
- private static final String ENDING = ".seednodes";
- private static final Collection cache = new HashSet<>();
- private final BisqEnvironment bisqEnvironment;
- private final String seedNodes;
+
+ private final Set seedNodeAddresses;
+ private final Set torSeedNodeAddresses;
+ private final Set localhostSeedNodeAddresses;
@Inject
- public DefaultSeedNodeRepository(BisqEnvironment environment,
- @Nullable @Named(NetworkOptionKeys.SEED_NODES_KEY) String seedNodes) {
- bisqEnvironment = environment;
- this.seedNodes = seedNodes;
+ public DefaultSeedNodeRepository(SeedNodeAddressLookup lookup) {
+ this.seedNodeAddresses = lookup.resolveNodeAddresses();
+ this.torSeedNodeAddresses = DefaultSeedNodeAddresses.DEFAULT_TOR_SEED_NODE_ADDRESSES;
+ this.localhostSeedNodeAddresses = DefaultSeedNodeAddresses.DEFAULT_LOCALHOST_SEED_NODE_ADDRESSES;
}
- private void reload() {
-
- // see if there are any seed nodes configured manually
- if(seedNodes != null && !seedNodes.isEmpty()) {
- cache.clear();
- Arrays.stream(seedNodes.split(",")).forEach(s -> cache.add(new NodeAddress(s)));
-
- return;
- }
-
- // else, we fetch the seed nodes from our resources
- try {
- // read appropriate file
- final URL file = DefaultSeedNodeRepository.class.getClassLoader().getResource(BisqEnvironment.getBaseCurrencyNetwork().name().toLowerCase() + ENDING);
- final BufferedReader seedNodeFile = new BufferedReader(new FileReader(file.getFile()));
-
- // only clear if we have a fresh data source (otherwise, an exception would prevent us from getting here)
- cache.clear();
-
- // refill the cache
- seedNodeFile.lines().forEach(s -> {
- final Matcher matcher = pattern.matcher(s);
- if(matcher.find())
- cache.add(new NodeAddress(matcher.group(1)));
- });
-
- // filter
- cache.removeAll(bisqEnvironment.getBannedSeedNodes().stream().map(s -> new NodeAddress(s)).collect(Collectors.toSet()));
- } catch (FileNotFoundException e) {
- e.printStackTrace();
- }
+ @Override
+ public Set getSeedNodeAddresses() {
+ return seedNodeAddresses;
}
- public Collection getSeedNodeAddresses() {
- if(cache.isEmpty())
- reload();
-
- return cache;
+ @Override
+ public String getOperator(NodeAddress nodeAddress) {
+ switch (nodeAddress.getFullAddress()) {
+ case "5quyxpxheyvzmb2d.onion:8000":
+ return "@miker";
+ case "ef5qnzx6znifo3df.onion:8000":
+ return "@manfredkarrer";
+ case "s67qglwhkgkyvr74.onion:8000":
+ return "@emzy";
+ case "jhgcy2won7xnslrb.onion:8000":
+ return "@manfredkarrer";
+ case "3f3cu2yw7u457ztq.onion:8000":
+ return "@manfredkarrer";
+ case "723ljisnynbtdohi.onion:8000":
+ return "@manfredkarrer";
+ case "rm7b56wbrcczpjvl.onion:8000":
+ return "@manfredkarrer";
+ case "fl3mmribyxgrv63c.onion:8000":
+ return "@manfredkarrer";
+ default:
+ return "Undefined";
+ }
}
+ @Override
public boolean isSeedNode(NodeAddress nodeAddress) {
- if(cache.isEmpty())
- reload();
- return cache.contains(nodeAddress);
+ return Stream.concat(localhostSeedNodeAddresses.stream(), torSeedNodeAddresses.stream())
+ .anyMatch(e -> e.equals(nodeAddress));
}
}
diff --git a/core/src/main/java/bisq/core/network/p2p/seed/ImmutableSetDecorator.java b/core/src/main/java/bisq/core/network/p2p/seed/ImmutableSetDecorator.java
new file mode 100644
index 00000000000..31fbb644b5f
--- /dev/null
+++ b/core/src/main/java/bisq/core/network/p2p/seed/ImmutableSetDecorator.java
@@ -0,0 +1,45 @@
+/*
+ * This file is part of Bisq.
+ *
+ * Bisq is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * Bisq is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with Bisq. If not, see .
+ */
+
+package bisq.core.network.p2p.seed;
+
+import com.google.common.collect.ImmutableSet;
+
+import java.util.AbstractSet;
+import java.util.Iterator;
+import java.util.Set;
+
+import org.jetbrains.annotations.NotNull;
+
+class ImmutableSetDecorator extends AbstractSet {
+ private final Set delegate;
+
+ public ImmutableSetDecorator(Set delegate) {
+ this.delegate = ImmutableSet.copyOf(delegate);
+ }
+
+ @NotNull
+ @Override
+ public Iterator iterator() {
+ return delegate.iterator();
+ }
+
+ @Override
+ public int size() {
+ return delegate.size();
+ }
+}
diff --git a/core/src/main/java/bisq/core/network/p2p/seed/SeedNodeAddressLookup.java b/core/src/main/java/bisq/core/network/p2p/seed/SeedNodeAddressLookup.java
new file mode 100644
index 00000000000..dc28119d615
--- /dev/null
+++ b/core/src/main/java/bisq/core/network/p2p/seed/SeedNodeAddressLookup.java
@@ -0,0 +1,106 @@
+/*
+ * This file is part of Bisq.
+ *
+ * Bisq is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * Bisq is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with Bisq. If not, see .
+ */
+
+package bisq.core.network.p2p.seed;
+
+import bisq.core.app.BisqEnvironment;
+
+import bisq.network.NetworkOptionKeys;
+import bisq.network.p2p.NodeAddress;
+
+import com.google.inject.name.Named;
+
+import javax.inject.Inject;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Optional;
+import java.util.Set;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.annotation.Nullable;
+
+public class SeedNodeAddressLookup {
+ private static final Logger log = LoggerFactory.getLogger(SeedNodeAddressLookup.class);
+
+ private final BisqEnvironment environment;
+ private final boolean isLocalHostUsed;
+ private final int networkId;
+ @Nullable
+ private final String myAddress;
+ @Nullable
+ private final String seedNodes;
+
+ @Inject
+ public SeedNodeAddressLookup(BisqEnvironment environment,
+ @Named(NetworkOptionKeys.USE_LOCALHOST_FOR_P2P) boolean useLocalhostForP2P,
+ @Named(NetworkOptionKeys.NETWORK_ID) int networkId,
+ @Nullable @Named(NetworkOptionKeys.MY_ADDRESS) String myAddress,
+ @Nullable @Named(NetworkOptionKeys.SEED_NODES_KEY) String seedNodes) {
+ this.environment = environment;
+ this.isLocalHostUsed = useLocalhostForP2P;
+ this.networkId = networkId;
+ this.myAddress = myAddress;
+ this.seedNodes = seedNodes;
+ }
+
+ public Set resolveNodeAddresses() {
+ SeedNodeAddresses allSeedNodeAddresses = getAllAddresses();
+
+ Set bannedHosts = getBannedHosts();
+ allSeedNodeAddresses = allSeedNodeAddresses.excludeByHost(bannedHosts);
+
+ if (myAddress != null) {
+ allSeedNodeAddresses = allSeedNodeAddresses.excludeByFullAddress(myAddress);
+ }
+
+ log.debug("We received banned seed nodes={}, seedNodeAddresses={}", bannedHosts, allSeedNodeAddresses);
+ return allSeedNodeAddresses;
+ }
+
+ private Set getBannedHosts() {
+ return Optional.ofNullable(environment.getBannedSeedNodes())
+ .map(HashSet::new)
+ .map(hosts -> (Set) hosts)
+ .orElse(Collections.emptySet());
+ }
+
+ private SeedNodeAddresses getAllAddresses() {
+ SeedNodeAddresses seedNodeAddresses = Optional.ofNullable(seedNodes)
+ .map(nodes -> SeedNodeAddresses.fromString(seedNodes))
+ .orElse(new SeedNodeAddresses(Collections.emptySet()));
+
+ if (seedNodeAddresses.isEmpty()) {
+ Set delegate = isLocalHostUsed
+ ? DefaultSeedNodeAddresses.DEFAULT_LOCALHOST_SEED_NODE_ADDRESSES
+ : DefaultSeedNodeAddresses.DEFAULT_TOR_SEED_NODE_ADDRESSES;
+ seedNodeAddresses = delegate.stream()
+ .filter(address -> isAddressFromNetwork(address, networkId))
+ .collect(SeedNodeAddresses.collector());
+ }
+ return seedNodeAddresses;
+ }
+
+ private static boolean isAddressFromNetwork(NodeAddress address, int networkId) {
+ String suffix = "0" + networkId;
+ int port = address.getPort();
+ String portAsString = String.valueOf(port);
+ return portAsString.endsWith(suffix);
+ }
+}
diff --git a/core/src/main/java/bisq/core/network/p2p/seed/SeedNodeAddresses.java b/core/src/main/java/bisq/core/network/p2p/seed/SeedNodeAddresses.java
new file mode 100644
index 00000000000..ad451e21722
--- /dev/null
+++ b/core/src/main/java/bisq/core/network/p2p/seed/SeedNodeAddresses.java
@@ -0,0 +1,67 @@
+/*
+ * This file is part of Bisq.
+ *
+ * Bisq is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * Bisq is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with Bisq. If not, see .
+ */
+
+package bisq.core.network.p2p.seed;
+
+import bisq.network.p2p.NodeAddress;
+
+import org.apache.commons.lang3.StringUtils;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.stream.Collector;
+import java.util.stream.Collectors;
+
+class SeedNodeAddresses extends ImmutableSetDecorator {
+
+ public SeedNodeAddresses(Set delegate) {
+ super(delegate);
+ }
+
+ public SeedNodeAddresses excludeByHost(Set hosts) {
+ Set copy = new HashSet<>(this);
+ copy.removeIf(address -> {
+ String hostName = address.getHostName();
+ return hosts.contains(hostName);
+ });
+ return new SeedNodeAddresses(copy);
+ }
+
+ public SeedNodeAddresses excludeByFullAddress(String fullAddress) {
+ Set copy = new HashSet<>(this);
+ copy.removeIf(address -> fullAddress.equals(address.getFullAddress()));
+ return new SeedNodeAddresses(copy);
+ }
+
+ public static Collector collector() {
+ return Collectors.collectingAndThen(Collectors.toSet(), SeedNodeAddresses::new);
+ }
+
+ public static SeedNodeAddresses fromString(String seedNodes) {
+ if (seedNodes.isEmpty()) {
+ return new SeedNodeAddresses(Collections.emptySet());
+ }
+
+ String trimmed = StringUtils.deleteWhitespace(seedNodes);
+ String[] nodes = trimmed.split(",");
+ return Arrays.stream(nodes)
+ .map(NodeAddress::new)
+ .collect(collector());
+ }
+}
diff --git a/core/src/main/resources/btc_dao_testnet.seednodes b/core/src/main/resources/btc_dao_testnet.seednodes
deleted file mode 100644
index fa63d9f5aed..00000000000
--- a/core/src/main/resources/btc_dao_testnet.seednodes
+++ /dev/null
@@ -1,5 +0,0 @@
-# nodeaddress.onion:port [(@owner)]
-fjr5w4eckjghqtnu.onion:8003
-3d56s6acbi3vk52v.onion:8003
-74w2sttlo4qk6go3.onion:8003
-jmc5ajqvtnzqaggm.onion:8003
diff --git a/core/src/main/resources/btc_mainnet.seednodes b/core/src/main/resources/btc_mainnet.seednodes
deleted file mode 100644
index 27a6f28feb9..00000000000
--- a/core/src/main/resources/btc_mainnet.seednodes
+++ /dev/null
@@ -1,9 +0,0 @@
-# nodeaddress.onion:port [(@owner)]
-5quyxpxheyvzmb2d.onion:8000 (@miker)
-s67qglwhkgkyvr74.onion:8000 (@emzy)
-ef5qnzx6znifo3df.onion:8000 (@freimair)
-jhgcy2won7xnslrb.onion:8000 (@freimair)
-3f3cu2yw7u457ztq.onion:8000 (@manfredkarrer)
-723ljisnynbtdohi.onion:8000 (@manfredkarrer)
-rm7b56wbrcczpjvl.onion:8000 (@manfredkarrer)
-fl3mmribyxgrv63c.onion:8000 (@manfredkarrer)
diff --git a/core/src/main/resources/btc_regtest.seednodes b/core/src/main/resources/btc_regtest.seednodes
deleted file mode 100644
index fb71abcae3e..00000000000
--- a/core/src/main/resources/btc_regtest.seednodes
+++ /dev/null
@@ -1,10 +0,0 @@
-# For development you need to change that to your local onion addresses
-# 1. Run a seed node with prog args: --bitcoinNetwork=regtest --nodePort=8002 --myAddress=rxdkppp3vicnbgqt:8002 --appName=bisq_seed_node_rxdkppp3vicnbgqt.onion_8002
-# 2. Find your local onion address in bisq_seed_node_rxdkppp3vicnbgqt.onion_8002/regtest/tor/hiddenservice/hostname
-# 3. Shut down the seed node
-# 4. Rename the directory with your local onion address
-# 5. Edit here your found onion address (new NodeAddress("YOUR_ONION.onion:8002")
-
-# nodeaddress.onion:port [(@owner)]
-rxdkppp3vicnbgqt.onion:8002
-4ie52dse64kaarxw.onion:8002
diff --git a/core/src/main/resources/btc_testnet.seednodes b/core/src/main/resources/btc_testnet.seednodes
deleted file mode 100644
index afc7c92300a..00000000000
--- a/core/src/main/resources/btc_testnet.seednodes
+++ /dev/null
@@ -1,2 +0,0 @@
-# nodeaddress.onion:port [(@owner)]
-# Bisq on BTC TESTNET has been discontinued
diff --git a/core/src/test/java/bisq/core/network/p2p/seed/DefaultSeedNodeRepositoryTest.java b/core/src/test/java/bisq/core/network/p2p/seed/DefaultSeedNodeRepositoryTest.java
deleted file mode 100644
index 85b00a44fc6..00000000000
--- a/core/src/test/java/bisq/core/network/p2p/seed/DefaultSeedNodeRepositoryTest.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * This file is part of Bisq.
- *
- * Bisq is free software: you can redistribute it and/or modify it
- * under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or (at
- * your option) any later version.
- *
- * Bisq is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
- * License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with Bisq. If not, see .
- */
-
-package bisq.core.network.p2p.seed;
-
-import bisq.core.app.BisqEnvironment;
-
-import bisq.network.p2p.NodeAddress;
-
-import org.springframework.core.env.PropertySource;
-
-import org.junit.Assert;
-import org.junit.Test;
-
-public class DefaultSeedNodeRepositoryTest {
-
- @Test
- public void getSeedNodes() {
- DefaultSeedNodeRepository DUT = new DefaultSeedNodeRepository(new BisqEnvironment(new PropertySource.StubPropertySource("name")), null);
- Assert.assertFalse(DUT.getSeedNodeAddresses().isEmpty());
- }
-
- @Test
- public void manualSeedNodes() {
- String seed1 = "asdf:8001";
- String seed2 = "fdsa:6001";
- String seedNodes = seed1 + "," + seed2;
- DefaultSeedNodeRepository DUT = new DefaultSeedNodeRepository(new BisqEnvironment(new PropertySource.StubPropertySource("name")), seedNodes);
- Assert.assertFalse(DUT.getSeedNodeAddresses().isEmpty());
- Assert.assertEquals(2, DUT.getSeedNodeAddresses().size());
- Assert.assertTrue(DUT.getSeedNodeAddresses().contains(new NodeAddress(seed1)));
- Assert.assertTrue(DUT.getSeedNodeAddresses().contains(new NodeAddress(seed2)));
- }
-}
diff --git a/core/src/test/java/bisq/core/network/p2p/seed/ImmutableSetDecoratorTest.java b/core/src/test/java/bisq/core/network/p2p/seed/ImmutableSetDecoratorTest.java
new file mode 100644
index 00000000000..b1cab1649d6
--- /dev/null
+++ b/core/src/test/java/bisq/core/network/p2p/seed/ImmutableSetDecoratorTest.java
@@ -0,0 +1,65 @@
+/*
+ * This file is part of Bisq.
+ *
+ * Bisq is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * Bisq is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with Bisq. If not, see .
+ */
+
+package bisq.core.network.p2p.seed;
+
+import com.google.common.collect.Sets;
+
+import java.util.Set;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertTrue;
+
+public class ImmutableSetDecoratorTest {
+ @Test(expected = UnsupportedOperationException.class)
+ public void testAdd() {
+ Set original = Sets.newHashSet(1, 2, 3);
+ Set decorator = new ImmutableSetDecorator<>(original);
+ decorator.add(4);
+ }
+
+ @Test(expected = UnsupportedOperationException.class)
+ public void testRemove() {
+ Set original = Sets.newHashSet(1, 2, 3);
+ Set decorator = new ImmutableSetDecorator<>(original);
+ decorator.remove(3);
+ }
+
+ @Test(expected = UnsupportedOperationException.class)
+ public void testClear() {
+ Set original = Sets.newHashSet(1, 2, 3);
+ Set decorator = new ImmutableSetDecorator<>(original);
+ decorator.clear();
+ }
+
+ @Test(expected = UnsupportedOperationException.class)
+ public void testRemoveWithIterator() {
+ Set original = Sets.newHashSet(1, 2, 3);
+ Set decorator = new ImmutableSetDecorator<>(original);
+ decorator.iterator().remove();
+ }
+
+ @Test
+ public void testBackingCollection() {
+ Set original = Sets.newHashSet(1, 2, 3);
+ Set decorator = new ImmutableSetDecorator<>(original);
+
+ original.remove(2);
+ assertTrue(decorator.contains(2));
+ }
+}
diff --git a/core/src/test/java/bisq/core/network/p2p/seed/SeedNodeAddressLookupTest.java b/core/src/test/java/bisq/core/network/p2p/seed/SeedNodeAddressLookupTest.java
new file mode 100644
index 00000000000..0ee76ef9686
--- /dev/null
+++ b/core/src/test/java/bisq/core/network/p2p/seed/SeedNodeAddressLookupTest.java
@@ -0,0 +1,55 @@
+/*
+ * This file is part of Bisq.
+ *
+ * Bisq is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * Bisq is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with Bisq. If not, see .
+ */
+
+package bisq.core.network.p2p.seed;
+
+import bisq.core.app.BisqEnvironment;
+
+import bisq.network.p2p.NodeAddress;
+
+import java.util.Collections;
+import java.util.Set;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.mockito.Mockito.mock;
+
+public class SeedNodeAddressLookupTest {
+
+
+ @Test
+ public void testResolveNodeAddressesWhenLocalAddressSpecified() {
+ SeedNodeAddressLookup lookup = new SeedNodeAddressLookup(
+ mock(BisqEnvironment.class), false, 0, "192.168.0.1:1234",
+ "192.168.0.1:1234, 192.168.0.2:9897");
+
+ Set actual = lookup.resolveNodeAddresses();
+ Set expected = Collections.singleton(new NodeAddress("192.168.0.2:9897"));
+ assertEquals(expected, actual);
+ }
+
+ @Test
+ public void testResolveNodeAddressesWhenSeedNodesAreNull() {
+ SeedNodeAddressLookup lookup = new SeedNodeAddressLookup(
+ mock(BisqEnvironment.class), false, 0, "192.168.0.1:1234", null);
+
+ Set actual = lookup.resolveNodeAddresses();
+ assertFalse(actual.isEmpty());
+ }
+}
diff --git a/core/src/test/java/bisq/core/network/p2p/seed/SeedNodeAddressesTest.java b/core/src/test/java/bisq/core/network/p2p/seed/SeedNodeAddressesTest.java
new file mode 100644
index 00000000000..b036f98faff
--- /dev/null
+++ b/core/src/test/java/bisq/core/network/p2p/seed/SeedNodeAddressesTest.java
@@ -0,0 +1,102 @@
+/*
+ * This file is part of Bisq.
+ *
+ * Bisq is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * Bisq is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with Bisq. If not, see .
+ */
+
+package bisq.core.network.p2p.seed;
+
+import bisq.network.p2p.NodeAddress;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+
+import java.security.Security;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+public class SeedNodeAddressesTest {
+
+
+ @Test
+ public void testCollector() {
+ List addresses = Lists.newArrayList(
+ new NodeAddress("192.168.0.1:1111"),
+ new NodeAddress("192.168.0.1:1111"),
+ new NodeAddress("192.168.0.2:2222"));
+ Set expected = new HashSet<>(addresses);
+
+ SeedNodeAddresses actual = addresses.stream()
+ .collect(SeedNodeAddresses.collector());
+
+ assertEquals(expected, actual);
+ }
+
+ @Test
+ public void testExcludeByFullAddress() {
+ Set delegate = Sets.newHashSet(
+ new NodeAddress("192.168.0.1:1111"),
+ new NodeAddress("192.168.0.2:2222"));
+ SeedNodeAddresses addresses = new SeedNodeAddresses(delegate);
+ SeedNodeAddresses actual = addresses.excludeByFullAddress("192.168.0.1:1111");
+
+ assertEquals(1, actual.size());
+ }
+
+ @Test
+ public void testExcludeByHost() {
+ Set delegate = Sets.newHashSet(
+ new NodeAddress("aaa:1111"),
+ new NodeAddress("aaa:2222"),
+ new NodeAddress("bbb:1111"),
+ new NodeAddress("bbb:2222"),
+ new NodeAddress("ccc:1111"),
+ new NodeAddress("ccc:2222"));
+ SeedNodeAddresses addresses = new SeedNodeAddresses(delegate);
+
+ Set hosts = Sets.newHashSet("aaa", "bbb");
+ SeedNodeAddresses actual = addresses.excludeByHost(hosts);
+
+ Set expected = Sets.newHashSet(
+ new NodeAddress("ccc:1111"),
+ new NodeAddress("ccc:2222"));
+
+ assertEquals(expected, actual);
+ }
+
+ @Test
+ public void testFromString() {
+ Set expected = Sets.newHashSet(
+ new NodeAddress("192.168.0.1:1111"),
+ new NodeAddress("192.168.0.2:2222"));
+ SeedNodeAddresses actual = SeedNodeAddresses.fromString("192.168.0.1:1111, 192.168.0.2:2222");
+ assertEquals(expected, actual);
+ }
+
+ @Test
+ public void testFromEmptyString() {
+ SeedNodeAddresses nodeAddresses = SeedNodeAddresses.fromString("");
+ assertTrue(nodeAddresses.isEmpty());
+ }
+}
diff --git a/core/src/test/resources/mainnet.seednodes b/core/src/test/resources/mainnet.seednodes
deleted file mode 100644
index fede53e55e5..00000000000
--- a/core/src/test/resources/mainnet.seednodes
+++ /dev/null
@@ -1,9 +0,0 @@
-# nodeaddress.onion:port [(@owner)]
-5quyxpxheyvzmb2d.onion:8000 (@miker)
-s67qglwhkgkyvr74.onion:8000 (@emzy)
-ef5qnzx6znifo3df.onion:8000 (@manfredkarrer)
-jhgcy2won7xnslrb.onion:8000 (@manfredkarrer)
-3f3cu2yw7u457ztq.onion:8000 (@manfredkarrer)
-723ljisnynbtdohi.onion:8000 (@manfredkarrer)
-rm7b56wbrcczpjvl.onion:8000 (@manfredkarrer)
-fl3mmribyxgrv63c.onion:8000 (@manfredkarrer)
diff --git a/core/src/test/resources/regtest.seednodes b/core/src/test/resources/regtest.seednodes
deleted file mode 100644
index fb71abcae3e..00000000000
--- a/core/src/test/resources/regtest.seednodes
+++ /dev/null
@@ -1,10 +0,0 @@
-# For development you need to change that to your local onion addresses
-# 1. Run a seed node with prog args: --bitcoinNetwork=regtest --nodePort=8002 --myAddress=rxdkppp3vicnbgqt:8002 --appName=bisq_seed_node_rxdkppp3vicnbgqt.onion_8002
-# 2. Find your local onion address in bisq_seed_node_rxdkppp3vicnbgqt.onion_8002/regtest/tor/hiddenservice/hostname
-# 3. Shut down the seed node
-# 4. Rename the directory with your local onion address
-# 5. Edit here your found onion address (new NodeAddress("YOUR_ONION.onion:8002")
-
-# nodeaddress.onion:port [(@owner)]
-rxdkppp3vicnbgqt.onion:8002
-4ie52dse64kaarxw.onion:8002
diff --git a/core/src/test/resources/testnet.seednodes b/core/src/test/resources/testnet.seednodes
deleted file mode 100644
index 77b6af07e63..00000000000
--- a/core/src/test/resources/testnet.seednodes
+++ /dev/null
@@ -1,7 +0,0 @@
-# nodeaddress.onion:port [(@owner)]
-snenz4mea65wigen.onion:8001
-fjr5w4eckjghqtnu.onion:8001
-3d56s6acbi3vk52v.onion:8001
-74w2sttlo4qk6go3.onion:8001
-gtif46mfxirv533z.onion:8001
-jmc5ajqvtnzqaggm.onion:8001
diff --git a/monitor/src/main/java/bisq/monitor/metric/P2PNetworkLoad.java b/monitor/src/main/java/bisq/monitor/metric/P2PNetworkLoad.java
index dcc03f1128a..1a5d0ea3078 100644
--- a/monitor/src/main/java/bisq/monitor/metric/P2PNetworkLoad.java
+++ b/monitor/src/main/java/bisq/monitor/metric/P2PNetworkLoad.java
@@ -32,12 +32,14 @@
import bisq.common.Clock;
import bisq.common.app.Capabilities;
+import bisq.common.app.Version;
import bisq.common.proto.network.NetworkEnvelope;
import bisq.common.proto.network.NetworkProtoResolver;
import bisq.core.app.BisqEnvironment;
import bisq.core.btc.BaseCurrencyNetwork;
import bisq.core.btc.BtcOptionKeys;
import bisq.core.network.p2p.seed.DefaultSeedNodeRepository;
+import bisq.core.network.p2p.seed.SeedNodeAddressLookup;
import bisq.core.proto.network.CoreNetworkProtoResolver;
import bisq.core.proto.persistable.CorePersistenceProtoResolver;
import bisq.monitor.AvailableTor;
@@ -160,6 +162,7 @@ protected void execute() {
// boot up P2P node
File storageDir = torHiddenServiceDir;
+ String seedNodes = "";
try {
BisqEnvironment environment = new BisqEnvironment(new PropertySource("name") {
@@ -174,7 +177,8 @@ public String getProperty(String name) {
NetworkProtoResolver networkProtoResolver = new CoreNetworkProtoResolver();
CorePersistenceProtoResolver persistenceProtoResolver = new CorePersistenceProtoResolver(null,
networkProtoResolver, storageDir);
- DefaultSeedNodeRepository seedNodeRepository = new DefaultSeedNodeRepository(environment, null);
+ DefaultSeedNodeRepository seedNodeRepository = new DefaultSeedNodeRepository(
+ new SeedNodeAddressLookup(environment, false, Version.getBaseCurrencyNetwork(), null, seedNodes));
PeerManager peerManager = new PeerManager(networkNode, seedNodeRepository, new Clock(),
persistenceProtoResolver, maxConnections, storageDir);
diff --git a/p2p/src/main/java/bisq/network/p2p/seed/SeedNodeRepository.java b/p2p/src/main/java/bisq/network/p2p/seed/SeedNodeRepository.java
index a59807ddb04..c5805af277d 100644
--- a/p2p/src/main/java/bisq/network/p2p/seed/SeedNodeRepository.java
+++ b/p2p/src/main/java/bisq/network/p2p/seed/SeedNodeRepository.java
@@ -19,11 +19,13 @@
import bisq.network.p2p.NodeAddress;
-import java.util.Collection;
+import java.util.Set;
public interface SeedNodeRepository {
boolean isSeedNode(NodeAddress nodeAddress);
- Collection getSeedNodeAddresses();
+ Set getSeedNodeAddresses();
+
+ String getOperator(NodeAddress nodeAddress);
}