diff --git a/core/src/main/java/bisq/core/CoreModule.java b/core/src/main/java/bisq/core/CoreModule.java index 65e88eb18dd..e22d44406ab 100644 --- a/core/src/main/java/bisq/core/CoreModule.java +++ b/core/src/main/java/bisq/core/CoreModule.java @@ -30,7 +30,6 @@ 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; @@ -99,7 +98,6 @@ 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 93404405a2c..7406840ea99 100644 --- a/core/src/main/java/bisq/core/app/BisqEnvironment.java +++ b/core/src/main/java/bisq/core/app/BisqEnvironment.java @@ -58,6 +58,7 @@ import java.io.FileOutputStream; import java.io.IOException; +import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Properties; @@ -192,7 +193,7 @@ public static boolean isDaoActivated(Environment environment) { protected final String btcNodes, seedNodes, ignoreDevMsg, useDevPrivilegeKeys, useDevMode, useTorForBtc, rpcUser, rpcPassword, rpcPort, rpcBlockNotificationPort, dumpBlockchainData, fullDaoNode, - myAddress, banList, dumpStatistics, maxMemory, socks5ProxyBtcAddress, + banList, dumpStatistics, maxMemory, socks5ProxyBtcAddress, torRcFile, torRcOptions, externalTorControlPort, externalTorPassword, externalTorCookieFile, socks5ProxyHttpAddress, useAllProvidedNodes, numConnectionForBtc, genesisTxId, genesisBlockHeight, referralId, daoActivated, msgThrottlePerSec, msgThrottlePer10Sec, sendMsgThrottleTrigger, sendMsgThrottleSleep; @@ -258,9 +259,6 @@ public BisqEnvironment(PropertySource commandLineProperties) { (String) commandLineProperties.getProperty(NetworkOptionKeys.SEED_NODES_KEY) : ""; - myAddress = commandLineProperties.containsProperty(NetworkOptionKeys.MY_ADDRESS) ? - (String) commandLineProperties.getProperty(NetworkOptionKeys.MY_ADDRESS) : - ""; banList = commandLineProperties.containsProperty(NetworkOptionKeys.BAN_LIST) ? (String) commandLineProperties.getProperty(NetworkOptionKeys.BAN_LIST) : ""; @@ -355,7 +353,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(",")) : null; + bannedSeedNodes = !bannedSeedNodesAsString.isEmpty() ? Arrays.asList(StringUtils.deleteWhitespace(bannedSeedNodesAsString).split(",")) : new ArrayList<>(); final String bannedBtcNodesAsString = getProperty(FilterManager.BANNED_BTC_NODES, ""); bannedBtcNodes = !bannedBtcNodesAsString.isEmpty() ? Arrays.asList(StringUtils.deleteWhitespace(bannedBtcNodesAsString).split(",")) : null; @@ -461,7 +459,6 @@ private PropertySource defaultProperties() { setProperty(CommonOptionKeys.USE_DEV_MODE, useDevMode); setProperty(NetworkOptionKeys.SEED_NODES_KEY, seedNodes); - setProperty(NetworkOptionKeys.MY_ADDRESS, myAddress); setProperty(NetworkOptionKeys.BAN_LIST, banList); setProperty(NetworkOptionKeys.TOR_DIR, Paths.get(btcNetworkDir, "tor").toString()); setProperty(NetworkOptionKeys.NETWORK_ID, String.valueOf(baseCurrencyNetwork.ordinal())); diff --git a/core/src/main/java/bisq/core/app/BisqExecutable.java b/core/src/main/java/bisq/core/app/BisqExecutable.java index 2cc321c0dad..b82c123aa76 100644 --- a/core/src/main/java/bisq/core/app/BisqExecutable.java +++ b/core/src/main/java/bisq/core/app/BisqExecutable.java @@ -341,11 +341,6 @@ protected void customizeOptionParsing(OptionParser parser) { .withRequiredArg() .describedAs("host:port[,...]"); - parser.accepts(NetworkOptionKeys.MY_ADDRESS, - "My own onion address (used for bootstrap nodes to exclude itself)") - .withRequiredArg() - .describedAs("host:port"); - parser.accepts(NetworkOptionKeys.BAN_LIST, "Nodes to exclude from network connections.") .withRequiredArg() 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 16d1c87ea70..35413918c2d 100644 --- a/core/src/main/java/bisq/core/app/misc/ModuleForAppWithP2p.java +++ b/core/src/main/java/bisq/core/app/misc/ModuleForAppWithP2p.java @@ -26,7 +26,6 @@ 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; @@ -77,7 +76,6 @@ 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 deleted file mode 100644 index d6ef2f5b5d7..00000000000 --- a/core/src/main/java/bisq/core/network/p2p/seed/DefaultSeedNodeAddresses.java +++ /dev/null @@ -1,97 +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.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 6c9e160bebf..9799267948e 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,59 +17,80 @@ 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.util.Set; -import java.util.stream.Stream; +import java.io.BufferedReader; +import java.io.InputStream; +import java.io.InputStreamReader; -public class DefaultSeedNodeRepository implements SeedNodeRepository { +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; - private final Set seedNodeAddresses; - private final Set torSeedNodeAddresses; - private final Set localhostSeedNodeAddresses; +import javax.annotation.Nullable; + +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; @Inject - public DefaultSeedNodeRepository(SeedNodeAddressLookup lookup) { - this.seedNodeAddresses = lookup.resolveNodeAddresses(); - this.torSeedNodeAddresses = DefaultSeedNodeAddresses.DEFAULT_TOR_SEED_NODE_ADDRESSES; - this.localhostSeedNodeAddresses = DefaultSeedNodeAddresses.DEFAULT_LOCALHOST_SEED_NODE_ADDRESSES; + public DefaultSeedNodeRepository(BisqEnvironment environment, + @Nullable @Named(NetworkOptionKeys.SEED_NODES_KEY) String seedNodes) { + bisqEnvironment = environment; + this.seedNodes = seedNodes; } - @Override - public Set getSeedNodeAddresses() { - return seedNodeAddresses; - } + 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))); - @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"; + return; } + + // else, we fetch the seed nodes from our resources + final InputStream fileInputStream = DefaultSeedNodeRepository.class.getClassLoader().getResourceAsStream(BisqEnvironment.getBaseCurrencyNetwork().name().toLowerCase() + ENDING); + final BufferedReader seedNodeFile = new BufferedReader(new InputStreamReader(fileInputStream)); + + // 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())); + } + + public Collection getSeedNodeAddresses() { + if(cache.isEmpty()) + reload(); + + return cache; } - @Override public boolean isSeedNode(NodeAddress nodeAddress) { - return Stream.concat(localhostSeedNodeAddresses.stream(), torSeedNodeAddresses.stream()) - .anyMatch(e -> e.equals(nodeAddress)); + if(cache.isEmpty()) + reload(); + return cache.contains(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 deleted file mode 100644 index 31fbb644b5f..00000000000 --- a/core/src/main/java/bisq/core/network/p2p/seed/ImmutableSetDecorator.java +++ /dev/null @@ -1,45 +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 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 deleted file mode 100644 index dc28119d615..00000000000 --- a/core/src/main/java/bisq/core/network/p2p/seed/SeedNodeAddressLookup.java +++ /dev/null @@ -1,106 +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.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 deleted file mode 100644 index ad451e21722..00000000000 --- a/core/src/main/java/bisq/core/network/p2p/seed/SeedNodeAddresses.java +++ /dev/null @@ -1,67 +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.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/java/bisq/core/util/BSFormatter.java b/core/src/main/java/bisq/core/util/BSFormatter.java index 8d6677b2a43..3f87a0f991d 100644 --- a/core/src/main/java/bisq/core/util/BSFormatter.java +++ b/core/src/main/java/bisq/core/util/BSFormatter.java @@ -51,6 +51,7 @@ import java.util.Date; import java.util.List; import java.util.Locale; +import java.util.TimeZone; import java.util.stream.Collectors; import lombok.extern.slf4j.Slf4j; @@ -482,9 +483,18 @@ public String languageCodesToString(List languageLocales) { } public String formatDateTime(Date date) { - return formatDateTime(date, - DateFormat.getDateInstance(DateFormat.DEFAULT, getLocale()), - DateFormat.getTimeInstance(DateFormat.DEFAULT, getLocale())); + return formatDateTime(date, true); + } + + public String formatDateTime(Date date, boolean useLocaleAndLocalTimezone) { + Locale locale = useLocaleAndLocalTimezone ? getLocale() : Locale.US; + DateFormat dateInstance = DateFormat.getDateInstance(DateFormat.DEFAULT, locale); + DateFormat timeInstance = DateFormat.getTimeInstance(DateFormat.DEFAULT, locale); + if (!useLocaleAndLocalTimezone) { + dateInstance.setTimeZone(TimeZone.getTimeZone("UTC")); + timeInstance.setTimeZone(TimeZone.getTimeZone("UTC")); + } + return formatDateTime(date, dateInstance, timeInstance); } public String formatDateTime(Date date, DateFormat dateFormatter, DateFormat timeFormatter) { diff --git a/core/src/main/resources/btc_dao_testnet.seednodes b/core/src/main/resources/btc_dao_testnet.seednodes new file mode 100644 index 00000000000..fa63d9f5aed --- /dev/null +++ b/core/src/main/resources/btc_dao_testnet.seednodes @@ -0,0 +1,5 @@ +# 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 new file mode 100644 index 00000000000..27a6f28feb9 --- /dev/null +++ b/core/src/main/resources/btc_mainnet.seednodes @@ -0,0 +1,9 @@ +# 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 new file mode 100644 index 00000000000..caa87710d68 --- /dev/null +++ b/core/src/main/resources/btc_regtest.seednodes @@ -0,0 +1,17 @@ +# By default developers use either port 2002 or 3002 or both as local seed nodes. If they want to use regtest +# with Tor they have to add a program argument to pass the custom onion address of the local Tor seed node. +# E.g. --seedNodes=YOUR_ONION.onion:2002 + +# To create your local onion addresses follow those steps: +# 1. Run a seed node with prog args: --bitcoinNetwork=regtest --nodePort=2002 --appName=bisq_seed_node_localhost_YOUR_ONION +# 2. Find your local onion address in bisq_seed_node_localhost_YOUR_ONION/regtest/tor/hiddenservice/hostname +# 3. Shut down the seed node +# 4. Rename YOUR_ONION at the directory with your local onion address as well as the appName program argument to reflect +# the real onion address. +# 5. Start the seed node again +# 6. Start the Bisq app which wants to connect to that seed node with program argument `--seedNodes=YOUR_ONION.onion:2002` + + +# nodeaddress.onion:port [(@owner)] +localhost:2002 +localhost:3002 diff --git a/core/src/main/resources/btc_testnet.seednodes b/core/src/main/resources/btc_testnet.seednodes new file mode 100644 index 00000000000..afc7c92300a --- /dev/null +++ b/core/src/main/resources/btc_testnet.seednodes @@ -0,0 +1,2 @@ +# 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 new file mode 100644 index 00000000000..85b00a44fc6 --- /dev/null +++ b/core/src/test/java/bisq/core/network/p2p/seed/DefaultSeedNodeRepositoryTest.java @@ -0,0 +1,48 @@ +/* + * 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 deleted file mode 100644 index b1cab1649d6..00000000000 --- a/core/src/test/java/bisq/core/network/p2p/seed/ImmutableSetDecoratorTest.java +++ /dev/null @@ -1,65 +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 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 deleted file mode 100644 index 0ee76ef9686..00000000000 --- a/core/src/test/java/bisq/core/network/p2p/seed/SeedNodeAddressLookupTest.java +++ /dev/null @@ -1,55 +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 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 deleted file mode 100644 index b036f98faff..00000000000 --- a/core/src/test/java/bisq/core/network/p2p/seed/SeedNodeAddressesTest.java +++ /dev/null @@ -1,102 +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.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 new file mode 100644 index 00000000000..fede53e55e5 --- /dev/null +++ b/core/src/test/resources/mainnet.seednodes @@ -0,0 +1,9 @@ +# 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 new file mode 100644 index 00000000000..fb71abcae3e --- /dev/null +++ b/core/src/test/resources/regtest.seednodes @@ -0,0 +1,10 @@ +# 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 new file mode 100644 index 00000000000..77b6af07e63 --- /dev/null +++ b/core/src/test/resources/testnet.seednodes @@ -0,0 +1,7 @@ +# 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/desktop/src/main/java/bisq/desktop/main/dao/governance/result/CycleListItem.java b/desktop/src/main/java/bisq/desktop/main/dao/governance/result/CycleListItem.java index 31c117f6495..108a993f935 100644 --- a/desktop/src/main/java/bisq/desktop/main/dao/governance/result/CycleListItem.java +++ b/desktop/src/main/java/bisq/desktop/main/dao/governance/result/CycleListItem.java @@ -46,10 +46,16 @@ public class CycleListItem { } public String getCycle() { - int displayIndex = resultsOfCycle.getCycleIndex() + 1; + return Res.get("dao.results.results.table.item.cycle", getCycleIndex(), getCycleDateTime(true)); + } + + public String getCycleDateTime(boolean useLocaleAndLocalTimezone) { long cycleStartTime = resultsOfCycle.getCycleStartTime(); - String dateTime = cycleStartTime > 0 ? bsqFormatter.formatDateTime(new Date(cycleStartTime)) : Res.get("shared.na"); - return Res.get("dao.results.results.table.item.cycle", displayIndex, dateTime); + return cycleStartTime > 0 ? bsqFormatter.formatDateTime(new Date(cycleStartTime), useLocaleAndLocalTimezone) : Res.get("shared.na"); + } + + public int getCycleIndex() { + return resultsOfCycle.getCycleIndex() + 1; } public String getNumProposals() { diff --git a/desktop/src/main/java/bisq/desktop/main/dao/governance/result/ProposalListItem.java b/desktop/src/main/java/bisq/desktop/main/dao/governance/result/ProposalListItem.java index eee333dfbda..ecd15d4955d 100644 --- a/desktop/src/main/java/bisq/desktop/main/dao/governance/result/ProposalListItem.java +++ b/desktop/src/main/java/bisq/desktop/main/dao/governance/result/ProposalListItem.java @@ -109,6 +109,10 @@ public String getDetails() { } public static String getProposalDetails(EvaluatedProposal evaluatedProposal, BsqFormatter bsqFormatter) { + return getProposalDetails(evaluatedProposal, bsqFormatter, true); + } + + public static String getProposalDetails(EvaluatedProposal evaluatedProposal, BsqFormatter bsqFormatter, boolean useDisplayString) { Proposal proposal = evaluatedProposal.getProposal(); switch (proposal.getType()) { case COMPENSATION_REQUEST: @@ -121,11 +125,12 @@ public static String getProposalDetails(EvaluatedProposal evaluatedProposal, Bsq return bsqFormatter.formatCoinWithCode(requestedBsq); case CHANGE_PARAM: ChangeParamProposal changeParamProposal = (ChangeParamProposal) proposal; - return changeParamProposal.getParam().getDisplayString(); + return useDisplayString ? changeParamProposal.getParam().getDisplayString() : changeParamProposal.getParam().name(); case BONDED_ROLE: RoleProposal roleProposal = (RoleProposal) proposal; Role role = roleProposal.getRole(); - return Res.get("dao.bond.bondedRoleType." + role.getBondedRoleType().name()); + String name = role.getBondedRoleType().name(); + return useDisplayString ? Res.get("dao.bond.bondedRoleType." + name) : name; case CONFISCATE_BOND: ConfiscateBondProposal confiscateBondProposal = (ConfiscateBondProposal) proposal; // TODO add info to bond diff --git a/desktop/src/main/java/bisq/desktop/main/dao/governance/result/VoteResultView.java b/desktop/src/main/java/bisq/desktop/main/dao/governance/result/VoteResultView.java index b58f8afa289..c4495229baa 100644 --- a/desktop/src/main/java/bisq/desktop/main/dao/governance/result/VoteResultView.java +++ b/desktop/src/main/java/bisq/desktop/main/dao/governance/result/VoteResultView.java @@ -952,13 +952,13 @@ private JsonElement getVotingHistoryJson() { sortedCycleListItemList.sorted(Comparator.comparing(CycleListItem::getCycleStartTime)).forEach(cycle -> { JsonObject cycleJson = new JsonObject(); - cycleJson.addProperty("cycleIndex", cycle.getResultsOfCycle().getCycleIndex()); - cycleJson.addProperty("cycle", cycle.getCycle()); + cycleJson.addProperty("cycleIndex", cycle.getCycleIndex()); + cycleJson.addProperty("cycleDateTime", cycle.getCycleDateTime(false)); cycleJson.addProperty("proposalsCount", cycle.getNumProposals()); cycleJson.addProperty("votesCount", cycle.getNumVotesAsString()); cycleJson.addProperty("voteWeight", cycle.getMeritAndStake()); cycleJson.addProperty("issuance", cycle.getIssuance()); - cycleJson.addProperty("startDate", cycle.getCycleStartTime()); + cycleJson.addProperty("startTime", cycle.getCycleStartTime()); cycleJson.addProperty("totalAcceptedVotes", cycle.getResultsOfCycle().getNumAcceptedVotes()); cycleJson.addProperty("totalRejectedVotes", cycle.getResultsOfCycle().getNumRejectedVotes()); @@ -969,11 +969,11 @@ private JsonElement getVotingHistoryJson() { evaluatedProposals.forEach(proposal -> { JsonObject proposalJson = new JsonObject(); - proposalJson.addProperty("dateTime", bsqFormatter.formatDateTime(proposal.getProposal().getCreationDate())); + proposalJson.addProperty("dateTime", bsqFormatter.formatDateTime(proposal.getProposal().getCreationDate(), false)); proposalJson.addProperty("name", proposal.getProposal().getName()); proposalJson.addProperty("link", proposal.getProposal().getLink()); - proposalJson.addProperty("proposalType", proposal.getProposal().getType().getShortDisplayName()); - proposalJson.addProperty("details", ProposalListItem.getProposalDetails(proposal, bsqFormatter)); + proposalJson.addProperty("proposalType", proposal.getProposal().getType().name()); + proposalJson.addProperty("details", ProposalListItem.getProposalDetails(proposal, bsqFormatter, false)); proposalJson.addProperty("voteResult", proposal.isAccepted() ? "Accepted" : "Rejected"); proposalJson.addProperty("txId", proposal.getProposalTxId()); proposalJson.addProperty("requiredQuorum", proposal.getRequiredQuorum()); @@ -990,7 +990,7 @@ private JsonElement getVotingHistoryJson() { switch (proposal.getProposal().getType()) { case BONDED_ROLE: RoleProposal roleProposal = (RoleProposal) proposal.getProposal(); - proposalJson.addProperty("roleType", roleProposal.getRole().getBondedRoleType().getDisplayString()); + proposalJson.addProperty("roleType", roleProposal.getRole().getBondedRoleType().name()); proposalJson.addProperty("requiredBond", roleProposal.getRole().getBondedRoleType().getRequiredBond()); proposalJson.addProperty("allowMultipleHolders", roleProposal.getRole().getBondedRoleType().isAllowMultipleHolders()); proposalJson.addProperty("unlockTimeInBlocks", roleProposal.getRole().getBondedRoleType().getUnlockTimeInBlocks()); @@ -998,7 +998,7 @@ private JsonElement getVotingHistoryJson() { break; case CHANGE_PARAM: ChangeParamProposal changeParamProposal = (ChangeParamProposal) proposal.getProposal(); - proposalJson.addProperty("param", changeParamProposal.getParam().getDisplayString()); + proposalJson.addProperty("param", changeParamProposal.getParam().name()); proposalJson.addProperty("paramValue", changeParamProposal.getParamValue()); proposalJson.addProperty("paramDefaultValue", changeParamProposal.getParam().getDefaultValue()); proposalJson.addProperty("paramMaxDecrease", changeParamProposal.getParam().getMaxDecrease()); @@ -1027,26 +1027,33 @@ private JsonElement getVotingHistoryJson() { JsonArray votesArray = new JsonArray(); evaluatedProposals.stream() .filter(evaluatedProposal -> evaluatedProposal.getProposal().equals(proposal.getProposal())) - .forEach(evaluatedProposal -> - cycle.getResultsOfCycle().getDecryptedVotesForCycle().forEach(decryptedBallotsWithMerits -> { - JsonObject voteJson = new JsonObject(); - Optional vote = decryptedBallotsWithMerits.getVote(proposal.getProposalTxId()); - if (vote.isPresent()) - voteJson.addProperty("vote", vote.get().isAccepted() ? "Accepted" : "Rejected"); - else - voteJson.addProperty("vote", "Ignored"); - - voteJson.addProperty("voteWeight", decryptedBallotsWithMerits.getStake()); - voteJson.addProperty("stake", decryptedBallotsWithMerits.getStake()); - voteJson.addProperty("blindTxId", decryptedBallotsWithMerits.getBlindVoteTxId()); - voteJson.addProperty("revealTxId", decryptedBallotsWithMerits.getVoteRevealTxId()); - - votesArray.add(voteJson); - })); + .forEach(evaluatedProposal -> { + List decryptedVotesForCycle = cycle.getResultsOfCycle().getDecryptedVotesForCycle(); + // Make sure the votes are sorted so we can easier compare json files from different users + decryptedVotesForCycle.sort(Comparator.comparing(DecryptedBallotsWithMerits::getBlindVoteTxId)); + decryptedVotesForCycle.forEach(decryptedBallotsWithMerits -> { + JsonObject voteJson = new JsonObject(); + Optional vote = decryptedBallotsWithMerits.getVote(proposal.getProposalTxId()); + if (vote.isPresent()) + voteJson.addProperty("vote", vote.get().isAccepted() ? "Accepted" : "Rejected"); + else + voteJson.addProperty("vote", "Ignored"); + + voteJson.addProperty("voteWeight", decryptedBallotsWithMerits.getMerit(daoStateService)); + voteJson.addProperty("stake", decryptedBallotsWithMerits.getStake()); + voteJson.addProperty("blindTxId", decryptedBallotsWithMerits.getBlindVoteTxId()); + voteJson.addProperty("revealTxId", decryptedBallotsWithMerits.getVoteRevealTxId()); + + votesArray.add(voteJson); + }); + }); + + proposalJson.addProperty("numberOfVotes", votesArray.size()); proposalJson.add("votes", votesArray); - proposalsArray.add(proposalJson); + proposalsArray.add(proposalJson); }); + cycleJson.addProperty("numberOfProposals", proposalsArray.size()); cycleJson.add("proposals", proposalsArray); cyclesArray.add(cycleJson); }); diff --git a/monitor/src/main/java/bisq/monitor/metric/P2PNetworkLoad.java b/monitor/src/main/java/bisq/monitor/metric/P2PNetworkLoad.java index 66f71a299f0..d102a29e638 100644 --- a/monitor/src/main/java/bisq/monitor/metric/P2PNetworkLoad.java +++ b/monitor/src/main/java/bisq/monitor/metric/P2PNetworkLoad.java @@ -34,14 +34,12 @@ import bisq.common.Clock; import bisq.common.app.Capabilities; import bisq.common.app.Capability; -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; @@ -167,7 +165,6 @@ protected void execute() { // boot up P2P node File storageDir = torHiddenServiceDir; - String seedNodes = ""; try { BisqEnvironment environment = new BisqEnvironment(new PropertySource("name") { @@ -182,8 +179,7 @@ public String getProperty(String name) { NetworkProtoResolver networkProtoResolver = new CoreNetworkProtoResolver(); CorePersistenceProtoResolver persistenceProtoResolver = new CorePersistenceProtoResolver(null, networkProtoResolver, storageDir); - DefaultSeedNodeRepository seedNodeRepository = new DefaultSeedNodeRepository( - new SeedNodeAddressLookup(environment, false, Version.getBaseCurrencyNetwork(), null, seedNodes)); + DefaultSeedNodeRepository seedNodeRepository = new DefaultSeedNodeRepository(environment, null); PeerManager peerManager = new PeerManager(networkNode, seedNodeRepository, new Clock(), persistenceProtoResolver, maxConnections, storageDir); diff --git a/p2p/src/main/java/bisq/network/NetworkOptionKeys.java b/p2p/src/main/java/bisq/network/NetworkOptionKeys.java index 765a5c6b8a0..0cca23093ac 100644 --- a/p2p/src/main/java/bisq/network/NetworkOptionKeys.java +++ b/p2p/src/main/java/bisq/network/NetworkOptionKeys.java @@ -24,7 +24,6 @@ public class NetworkOptionKeys { public static final String PORT_KEY = "nodePort"; public static final String NETWORK_ID = "networkId"; public static final String SEED_NODES_KEY = "seedNodes"; - public static final String MY_ADDRESS = "myAddress"; public static final String BAN_LIST = "banList"; //SOCKS_5_PROXY_BTC_ADDRESS used in network module so dont move it to BtcOptionKeys public static final String SOCKS_5_PROXY_BTC_ADDRESS = "socks5ProxyBtcAddress"; diff --git a/p2p/src/main/java/bisq/network/p2p/NetworkNodeProvider.java b/p2p/src/main/java/bisq/network/p2p/NetworkNodeProvider.java index 6a5b7c78893..04349561be1 100644 --- a/p2p/src/main/java/bisq/network/p2p/NetworkNodeProvider.java +++ b/p2p/src/main/java/bisq/network/p2p/NetworkNodeProvider.java @@ -42,7 +42,6 @@ public class NetworkNodeProvider implements Provider { public NetworkNodeProvider(NetworkProtoResolver networkProtoResolver, BridgeAddressProvider bridgeAddressProvider, @Named(NetworkOptionKeys.USE_LOCALHOST_FOR_P2P) boolean useLocalhostForP2P, - @Named(NetworkOptionKeys.MY_ADDRESS) String address, @Named(NetworkOptionKeys.PORT_KEY) int port, @Named(NetworkOptionKeys.TOR_DIR) File torDir, @Named(NetworkOptionKeys.TORRC_FILE) String torrcFile, @@ -53,7 +52,7 @@ public NetworkNodeProvider(NetworkProtoResolver networkProtoResolver, @Named(NetworkOptionKeys.TOR_STREAM_ISOLATION) boolean streamIsolation, @Named(NetworkOptionKeys.EXTERNAL_TOR_USE_SAFECOOKIE) boolean useSafeCookieAuthentication ) { networkNode = useLocalhostForP2P ? - new LocalhostNetworkNode(address, port, networkProtoResolver) : + new LocalhostNetworkNode(port, networkProtoResolver) : new TorNetworkNode(port, networkProtoResolver, streamIsolation, !controlPort.isEmpty() ? new RunningTor(torDir, Integer.parseInt(controlPort), password, cookieFile, useSafeCookieAuthentication) : diff --git a/p2p/src/main/java/bisq/network/p2p/P2PModule.java b/p2p/src/main/java/bisq/network/p2p/P2PModule.java index e94260d9b82..3618873a4ce 100644 --- a/p2p/src/main/java/bisq/network/p2p/P2PModule.java +++ b/p2p/src/main/java/bisq/network/p2p/P2PModule.java @@ -88,7 +88,6 @@ protected void configure() { Integer networkId = environment.getProperty(NetworkOptionKeys.NETWORK_ID, int.class, 1); bind(int.class).annotatedWith(Names.named(NetworkOptionKeys.NETWORK_ID)).toInstance(networkId); bindConstant().annotatedWith(named(NetworkOptionKeys.SEED_NODES_KEY)).to(environment.getRequiredProperty(NetworkOptionKeys.SEED_NODES_KEY)); - bindConstant().annotatedWith(named(NetworkOptionKeys.MY_ADDRESS)).to(environment.getRequiredProperty(NetworkOptionKeys.MY_ADDRESS)); bindConstant().annotatedWith(named(NetworkOptionKeys.BAN_LIST)).to(environment.getRequiredProperty(NetworkOptionKeys.BAN_LIST)); bindConstant().annotatedWith(named(NetworkOptionKeys.SOCKS_5_PROXY_BTC_ADDRESS)).to(environment.getRequiredProperty(NetworkOptionKeys.SOCKS_5_PROXY_BTC_ADDRESS)); bindConstant().annotatedWith(named(NetworkOptionKeys.SOCKS_5_PROXY_HTTP_ADDRESS)).to(environment.getRequiredProperty(NetworkOptionKeys.SOCKS_5_PROXY_HTTP_ADDRESS)); diff --git a/p2p/src/main/java/bisq/network/p2p/network/LocalhostNetworkNode.java b/p2p/src/main/java/bisq/network/p2p/network/LocalhostNetworkNode.java index ca0326419da..b49bff1e737 100644 --- a/p2p/src/main/java/bisq/network/p2p/network/LocalhostNetworkNode.java +++ b/p2p/src/main/java/bisq/network/p2p/network/LocalhostNetworkNode.java @@ -41,8 +41,6 @@ public class LocalhostNetworkNode extends NetworkNode { private static int simulateTorDelayTorNode = 500; private static int simulateTorDelayHiddenService = 500; - private String address; - public static void setSimulateTorDelayTorNode(int simulateTorDelayTorNode) { LocalhostNetworkNode.simulateTorDelayTorNode = simulateTorDelayTorNode; } @@ -56,15 +54,8 @@ public static void setSimulateTorDelayHiddenService(int simulateTorDelayHiddenSe // Constructor /////////////////////////////////////////////////////////////////////////////////////////// - public LocalhostNetworkNode(String address, int port, NetworkProtoResolver networkProtoResolver) { - super(port, networkProtoResolver); - if (null != address && !address.trim().isEmpty()) { - this.address = address; - } - } - public LocalhostNetworkNode(int port, NetworkProtoResolver networkProtoResolver) { - this(null, port, networkProtoResolver); + super(port, networkProtoResolver); } @Override @@ -76,6 +67,8 @@ public void start(@Nullable SetupListener setupListener) { // simulate tor connection delay UserThread.runAfter(() -> { + nodeAddressProperty.set(new NodeAddress("localhost", servicePort)); + setupListeners.stream().forEach(SetupListener::onTorNodeReady); // simulate tor HS publishing delay @@ -86,10 +79,6 @@ public void start(@Nullable SetupListener setupListener) { e.printStackTrace(); log.error("Exception at startServer: " + e.getMessage()); } - final NodeAddress nodeAddress = address == null ? - new NodeAddress("localhost", servicePort) : - new NodeAddress(address); - nodeAddressProperty.set(nodeAddress); setupListeners.stream().forEach(SetupListener::onHiddenServicePublished); }, simulateTorDelayTorNode, TimeUnit.MILLISECONDS); }, simulateTorDelayHiddenService, TimeUnit.MILLISECONDS); diff --git a/p2p/src/main/java/bisq/network/p2p/network/NetworkNode.java b/p2p/src/main/java/bisq/network/p2p/network/NetworkNode.java index 75b4947daad..8ff8e04334d 100644 --- a/p2p/src/main/java/bisq/network/p2p/network/NetworkNode.java +++ b/p2p/src/main/java/bisq/network/p2p/network/NetworkNode.java @@ -113,6 +113,11 @@ public SettableFuture sendMessage(@NotNull NodeAddress peersNodeAddr final SettableFuture resultFuture = SettableFuture.create(); ListenableFuture future = executorService.submit(() -> { Thread.currentThread().setName("NetworkNode:SendMessage-to-" + peersNodeAddress); + + if(peersNodeAddress.equals(getNodeAddress())){ + throw new ConnectException("We do not send a message to ourselves"); + } + OutboundConnection outboundConnection = null; try { // can take a while when using tor @@ -450,4 +455,9 @@ private void printInboundConnections() { public NodeAddress getNodeAddress() { return nodeAddressProperty.get(); } + + @Nullable + public ObjectProperty getNodeAddressProperty() { + return nodeAddressProperty; + } } diff --git a/p2p/src/main/java/bisq/network/p2p/network/TorNetworkNode.java b/p2p/src/main/java/bisq/network/p2p/network/TorNetworkNode.java index 1ae189f8279..aad0eb3a585 100644 --- a/p2p/src/main/java/bisq/network/p2p/network/TorNetworkNode.java +++ b/p2p/src/main/java/bisq/network/p2p/network/TorNetworkNode.java @@ -249,11 +249,12 @@ private void createTorAndHiddenService(int localPort, int servicePort) { try { // get tor Tor.setDefault(torMode.getTor()); - UserThread.execute(() -> setupListeners.forEach(SetupListener::onTorNodeReady)); // start hidden service long ts2 = new Date().getTime(); hiddenServiceSocket = new HiddenServiceSocket(localPort, torMode.getHiddenServiceDirectory(), servicePort); + nodeAddressProperty.set(new NodeAddress(hiddenServiceSocket.getServiceName() + ":" + hiddenServiceSocket.getHiddenServicePort())); + UserThread.execute(() -> setupListeners.forEach(SetupListener::onTorNodeReady)); hiddenServiceSocket.addReadyListener(socket -> { try { log.info("\n################################################################\n" + diff --git a/p2p/src/main/java/bisq/network/p2p/peers/getdata/RequestDataManager.java b/p2p/src/main/java/bisq/network/p2p/peers/getdata/RequestDataManager.java index ffdee6072df..644f65ca9a3 100644 --- a/p2p/src/main/java/bisq/network/p2p/peers/getdata/RequestDataManager.java +++ b/p2p/src/main/java/bisq/network/p2p/peers/getdata/RequestDataManager.java @@ -38,6 +38,8 @@ import javax.inject.Inject; +import javafx.beans.property.SimpleObjectProperty; + import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -109,8 +111,7 @@ public interface Listener { public RequestDataManager(NetworkNode networkNode, SeedNodeRepository seedNodeRepository, P2PDataStorage dataStorage, - PeerManager peerManager, - @javax.annotation.Nullable @Named(NetworkOptionKeys.MY_ADDRESS) String myAddress) { + PeerManager peerManager) { this.networkNode = networkNode; this.dataStorage = dataStorage; this.peerManager = peerManager; @@ -121,14 +122,21 @@ public RequestDataManager(NetworkNode networkNode, this.seedNodeAddresses = new HashSet<>(seedNodeRepository.getSeedNodeAddresses()); - // If we are a seed node we use more redundancy at startup to be sure we get all data. - // We cannot use networkNode.getNodeAddress() as nodeAddress as that is null at this point, so we use - // new NodeAddress(myAddress) for checking if we are a seed node. - // seedNodeAddresses do not contain my own address as that gets filtered out - if (myAddress != null && !myAddress.isEmpty() && seedNodeRepository.isSeedNode(new NodeAddress(myAddress))) { - NUM_SEEDS_FOR_PRELIMINARY_REQUEST = 3; - NUM_ADDITIONAL_SEEDS_FOR_UPDATE_REQUEST = 2; - } + this.networkNode.getNodeAddressProperty().addListener(observable -> { + + NodeAddress myAddress = (NodeAddress) ((SimpleObjectProperty) observable).get(); + + seedNodeAddresses.remove(myAddress); + + // If we are a seed node we use more redundancy at startup to be sure we get all data. + // We cannot use networkNode.getNodeAddress() as nodeAddress as that is null at this point, so we use + // new NodeAddress(myAddress) for checking if we are a seed node. + // seedNodeAddresses do not contain my own address as that gets filtered out + if (myAddress != null && seedNodeRepository.isSeedNode(myAddress)) { + NUM_SEEDS_FOR_PRELIMINARY_REQUEST = 3; + NUM_ADDITIONAL_SEEDS_FOR_UPDATE_REQUEST = 2; + } + }); } public void shutDown() { 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 c5805af277d..a59807ddb04 100644 --- a/p2p/src/main/java/bisq/network/p2p/seed/SeedNodeRepository.java +++ b/p2p/src/main/java/bisq/network/p2p/seed/SeedNodeRepository.java @@ -19,13 +19,11 @@ import bisq.network.p2p.NodeAddress; -import java.util.Set; +import java.util.Collection; public interface SeedNodeRepository { boolean isSeedNode(NodeAddress nodeAddress); - Set getSeedNodeAddresses(); - - String getOperator(NodeAddress nodeAddress); + Collection getSeedNodeAddresses(); } diff --git a/p2p/src/test/java/bisq/network/p2p/DummySeedNode.java b/p2p/src/test/java/bisq/network/p2p/DummySeedNode.java index 0b9f6bc3578..ab9e6740f95 100644 --- a/p2p/src/test/java/bisq/network/p2p/DummySeedNode.java +++ b/p2p/src/test/java/bisq/network/p2p/DummySeedNode.java @@ -84,7 +84,6 @@ public DummySeedNode(String defaultUserDataDir) { // Example usage: -myAddress=lmvdenjkyvx2ovga.onion:8001 -networkId=0 -maxConnections=20 -useLocalhostForP2P=false -seedNodes=si3uu56adkyqkldl.onion:8002|eo5ay2lyzrfvx2nr.onion:8002 -ignore=4543y2lyzrfvx2nr.onion:8002|876572lyzrfvx2nr.onion:8002 public static final String USAGE = "Usage:\n" + - "--myAddress=\n" + "--networkId=[0|1|2] (Mainnet = 0, TestNet = 1, Regtest = 2)\n" + "--maxConnections=\n" + "--useLocalhostForP2P=[true|false]\n" + @@ -100,12 +99,7 @@ public void processArgs(String[] args) { String arg = arg1; if (arg.startsWith("--")) arg = arg.substring(2); - if (arg.startsWith(NetworkOptionKeys.MY_ADDRESS)) { - arg = arg.substring(NetworkOptionKeys.MY_ADDRESS.length() + 1); - checkArgument(arg.contains(":") && arg.split(":").length == 2 && arg.split(":")[1].length() > 3, "Wrong program argument: " + arg); - mySeedNodeAddress = new NodeAddress(arg); - log.debug("From processArgs: mySeedNodeAddress=" + mySeedNodeAddress); - } else if (arg.startsWith(NetworkOptionKeys.NETWORK_ID)) { + if (arg.startsWith(NetworkOptionKeys.NETWORK_ID)) { arg = arg.substring(NetworkOptionKeys.NETWORK_ID.length() + 1); networkId = Integer.parseInt(arg); log.debug("From processArgs: networkId=" + networkId);