Add and change btc, seed and provider nodes. Use only HS nodes if tor is used for btcj

This commit is contained in:
Manfred Karrer 2017-12-18 23:37:32 +01:00
parent a5e3072772
commit 852d4c5ba5
No known key found for this signature in database
GPG key ID: 401250966A6B2C46
8 changed files with 104 additions and 162 deletions

View file

@ -17,6 +17,7 @@
package io.bisq.common.crypto;
import com.google.common.annotations.VisibleForTesting;
import com.google.protobuf.ByteString;
import io.bisq.common.proto.network.NetworkPayload;
import io.bisq.common.util.Utilities;
@ -43,10 +44,10 @@ public final class PubKeyRing implements NetworkPayload, RestrictedByContractJso
@Nullable
private final String pgpPubKeyAsPem;
private PublicKey signaturePubKey;
private PublicKey encryptionPubKey;
private transient PublicKey signaturePubKey;
private transient PublicKey encryptionPubKey;
@Nullable
private PGPPublicKey pgpPubKey;
private transient PGPPublicKey pgpPubKey;
public PubKeyRing(PublicKey signaturePubKey, PublicKey encryptionPubKey, @Nullable PGPPublicKey pgpPubKey) {
this.signaturePubKeyBytes = Sig.getPublicKeyBytes(signaturePubKey);
@ -63,6 +64,7 @@ public final class PubKeyRing implements NetworkPayload, RestrictedByContractJso
// PROTO BUFFER
///////////////////////////////////////////////////////////////////////////////////////////
@VisibleForTesting
public PubKeyRing(byte[] signaturePubKeyBytes, byte[] encryptionPubKeyBytes, @Nullable String pgpPubKeyAsPem) {
this.signaturePubKeyBytes = signaturePubKeyBytes;
this.encryptionPubKeyBytes = encryptionPubKeyBytes;

View file

@ -28,7 +28,6 @@ import java.util.Arrays;
import java.util.List;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
// Managed here: https://github.com/bisq-network/roles/issues/39
@Slf4j
@ -44,23 +43,33 @@ public class BitcoinNodes {
public List<BtcNode> getProvidedBtcNodes() {
return useProvidedBtcNodes() ?
Arrays.asList(
BtcNode.fromHostNameAddressAndPort("kirsche.emzy.de", "78.47.61.83", BtcNode.DEFAULT_PORT, "https://github.com/emzy"),
BtcNode.fromAddressAndPort("62.75.210.81", BtcNode.DEFAULT_PORT, "https://github.com/emzy"), // used also for r3dsojfhwcm7x7p6, not used: c6ac4jdfyeiakex2
BtcNode.fromAddressAndPort("163.172.171.119", BtcNode.DEFAULT_PORT, "https://github.com/emzy"), // not used: sjyzmwwu6diiit3r
// ManfredKarrer
new BtcNode("btc1.0-2-1.net", "r3dsojfhwcm7x7p6.onion", "159.89.16.222", BtcNode.DEFAULT_PORT, "https://github.com/ManfredKarrer"),
new BtcNode("btc2.0-2-1.net", "vlf5i3grro3wux24.onion", "165.227.34.56", BtcNode.DEFAULT_PORT, "https://github.com/ManfredKarrer"),
new BtcNode("btc3.0-2-1.net", "i3a5xtzfm4xwtybd.onion", "165.227.44.202", BtcNode.DEFAULT_PORT, "https://github.com/ManfredKarrer"),
BtcNode.fromHostNameAddressAndPort("bitcoin.christophatteneder.com", "174.138.35.229", BtcNode.DEFAULT_PORT, "https://github.com/ripcurlx"),
BtcNode.fromHostNameAddressAndPort("btc.vante.me", "138.68.117.247", BtcNode.DEFAULT_PORT, "https://github.com/mrosseel"),
// emzy
new BtcNode("kirsche.emzy.de", null, "78.47.61.83", BtcNode.DEFAULT_PORT, "https://github.com/emzy"),
new BtcNode("node2.emzy.de", "c6ac4jdfyeiakex2.onion", "62.75.210.81", BtcNode.DEFAULT_PORT, "https://github.com/emzy"),
new BtcNode("node1.emzy.de", "sjyzmwwu6diiit3r.onion", "163.172.171.119", BtcNode.DEFAULT_PORT, "https://github.com/emzy"),
new BtcNode(null, "poyvpdt762gllauu.onion", null, BtcNode.DEFAULT_PORT, "https://github.com/emzy"),
BtcNode.fromHostNameAddressAndPort("bitcoin4-fullnode.csg.uzh.ch", "192.41.136.217", BtcNode.DEFAULT_PORT, "https://github.com/tbocek"),
BtcNode.fromHostNameAddressAndPort("bcwat.ch", "5.189.166.193", BtcNode.DEFAULT_PORT, "https://github.com/sgeisler"),
BtcNode.fromHostNameAddressAndPort("btc.jochen-hoenicke.de", "37.221.198.57", BtcNode.DEFAULT_PORT, "https://github.com/jhoenicke"),
// ripcurlx
new BtcNode("bitcoin.christophatteneder.com", "lgkvbvro67jomosw.onion", "174.138.35.229", BtcNode.DEFAULT_PORT, "https://github.com/ripcurlx"),
BtcNode.fromHostName("poyvpdt762gllauu.onion", BtcNode.DEFAULT_PORT, "https://github.com/emzy"), // onion only
BtcNode.fromHostName("r3dsojfhwcm7x7p6.onion", BtcNode.DEFAULT_PORT, "https://github.com/emzy"), // 62.75.210.81
BtcNode.fromHostName("vlf5i3grro3wux24.onion", BtcNode.DEFAULT_PORT, "https://github.com/alexej996"), // onion only
BtcNode.fromHostName("3r44ddzjitznyahw.onion", BtcNode.DEFAULT_PORT, "https://github.com/sqrrm"), // not used: 185.25.48.184
BtcNode.fromHostName("i3a5xtzfm4xwtybd.onion", BtcNode.DEFAULT_PORT, "https://github.com/sqrrm"), // not used: 80.233.134.60
BtcNode.fromHostName("mxdtrjhe2yfsx3pg.onion", BtcNode.DEFAULT_PORT, "https://github.com/mrosseel") // onion only*/
// mrosseel
new BtcNode("btc.vante.me", null, "138.68.117.247", BtcNode.DEFAULT_PORT, "https://github.com/mrosseel"),
new BtcNode(null, "mxdtrjhe2yfsx3pg.onion", null, BtcNode.DEFAULT_PORT, "https://github.com/mrosseel"),
// sqrrm
new BtcNode("btc4.0-2-1.net", "3r44ddzjitznyahw.onion", "185.25.48.184", BtcNode.DEFAULT_PORT, "https://github.com/sqrrm"), //TODO change dns
// sgeisler
new BtcNode("bcwat.ch", "z33nukt7ngik3cpe.onion", "5.189.166.193", BtcNode.DEFAULT_PORT, "https://github.com/sgeisler"),
// others
new BtcNode("btc.jochen-hoenicke.de", null, "37.221.198.57", BtcNode.DEFAULT_PORT, "https://github.com/jhoenicke"),
new BtcNode("bitcoin4-fullnode.csg.uzh.ch", null, "192.41.136.217", BtcNode.DEFAULT_PORT, "https://github.com/tbocek")
) :
new ArrayList<>();
}
@ -74,6 +83,8 @@ public class BitcoinNodes {
public static class BtcNode {
private static final int DEFAULT_PORT = BisqEnvironment.getParameters().getPort(); //8333
@Nullable
private final String onionAddress;
@Nullable
private final String hostName;
@Nullable
@ -83,69 +94,30 @@ public class BitcoinNodes {
private int port = DEFAULT_PORT;
/**
* @param fullAddress [hostName:port | IPv4 address:port]
* @param fullAddress [IPv4 address:port or onion:port]
* @return BtcNode instance
*/
public static BtcNode fromFullAddress(String fullAddress) {
String[] parts = fullAddress.split(":");
checkArgument(parts.length > 0);
if (parts.length == 1) {
return BtcNode.fromHostName(parts[0], DEFAULT_PORT, null);
} else {
checkArgument(parts.length == 2);
return BtcNode.fromHostNameAndPort(parts[0], Integer.valueOf(parts[1]), null);
}
final String host = parts[0];
int port = DEFAULT_PORT;
if (parts.length == 2)
port = Integer.valueOf(parts[1]);
return host.contains(".onion") ? new BtcNode(null, host, null, port, null) : new BtcNode(null, null, host, port, null);
}
public static BtcNode fromHostName(String hostName, int port, @Nullable String operator) {
return new BtcNode(hostName, null, port, operator);
}
public static BtcNode fromAddress(String address, @Nullable String operator) {
return new BtcNode(null, address, operator);
}
public static BtcNode fromHostNameAndPort(String hostName, int port, @Nullable String operator) {
return new BtcNode(hostName, null, port, operator);
}
public static BtcNode fromHostNameAndAddress(String hostName, String address, @Nullable String operator) {
return new BtcNode(hostName, address, operator);
}
public static BtcNode fromHostNameAddressAndPort(String hostName, String address, int port, @Nullable String operator) {
return new BtcNode(hostName, address, port, operator);
}
public static BtcNode fromAddressAndPort(String address, int port, @Nullable String operator) {
return new BtcNode(null, address, port, operator);
}
private BtcNode(@Nullable String hostName, @Nullable String address, int port, @Nullable String operator) {
public BtcNode(@Nullable String hostName, @Nullable String onionAddress, @Nullable String address, int port, @Nullable String operator) {
this.hostName = hostName;
this.onionAddress = onionAddress;
this.address = address;
this.port = port;
this.operator = operator;
if (address == null)
checkNotNull(hostName, "hostName must not be null if address is null");
else if (hostName == null)
checkNotNull(address, "address must not be null if hostName is null");
}
private BtcNode(@Nullable String hostName, @Nullable String address, @Nullable String operator) {
this.hostName = hostName;
this.address = address;
this.operator = operator;
if (address == null)
checkNotNull(hostName, "hostName must not be null if address is null");
else if (hostName == null)
checkNotNull(address, "address must not be null if hostName is null");
}
public boolean isHiddenService() {
return hostName != null && hostName.endsWith("onion");
public boolean hasOnionAddress() {
return onionAddress != null;
}
public String getHostNameOrAddress() {
@ -155,9 +127,8 @@ public class BitcoinNodes {
return address;
}
public String getHostNameOrAddressWithPort() {
log.error(getHostNameOrAddress() + ":" + port);
return getHostNameOrAddress() + ":" + port;
public boolean hasClearNetAddress() {
return hostName != null || address != null;
}
}
}

View file

@ -32,10 +32,10 @@ import io.bisq.common.storage.FileUtil;
import io.bisq.core.app.BisqEnvironment;
import io.bisq.core.btc.*;
import io.bisq.core.user.Preferences;
import io.bisq.network.DnsLookupTor;
import io.bisq.network.Socks5MultiDiscovery;
import io.bisq.network.Socks5ProxyProvider;
import javafx.beans.property.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.bitcoinj.core.*;
import org.bitcoinj.core.listeners.DownloadProgressTracker;
@ -46,8 +46,6 @@ import org.bitcoinj.utils.Threading;
import org.bitcoinj.wallet.DeterministicSeed;
import org.bitcoinj.wallet.Wallet;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.annotation.Nullable;
import javax.inject.Named;
@ -70,9 +68,8 @@ import static com.google.common.base.Preconditions.checkNotNull;
// Setup wallets and use WalletConfig for BitcoinJ wiring.
// Other like WalletConfig we are here always on the user thread. That is one reason why we do not
// merge WalletsSetup with WalletConfig to one class.
@Slf4j
public class WalletsSetup {
private static final Logger log = LoggerFactory.getLogger(WalletsSetup.class);
private static final long STARTUP_TIMEOUT_SEC = 120;
private final String btcWalletFileName;
private static final String BSQ_WALLET_FILE_NAME = "bisq_BSQ.wallet";
@ -301,55 +298,41 @@ public class WalletsSetup {
final boolean useTorForBitcoinJ = socks5Proxy != null;
List<PeerAddress> peerAddressList = new ArrayList<>();
btcNodeList.forEach(btcNode -> {
if (useTorForBitcoinJ) {
if (btcNode.isHiddenService()) {
// no DNS lookup for onion addresses
log.info("We add a onion node with btcNode={}", btcNode);
final String hostName = btcNode.getHostName();
if (hostName != null) {
try {
// OnionCat.onionHostToInetAddress converts onion to ipv6 representation
final InetAddress inetAddress = OnionCat.onionHostToInetAddress(hostName);
final PeerAddress peerAddress = new PeerAddress(hostName, btcNode.getPort());
// inetAddress is not used but required for wallet persistence. Throws nullpointer if not set.
peerAddress.setAddr(inetAddress);
peerAddressList.add(peerAddress);
} catch (UnknownHostException e) {
log.error("OnionCat.onionHostToInetAddress() failed with btcNode={}, error={}", btcNode.toString(), e.toString());
e.printStackTrace();
}
} else {
log.error("hostName is null for btcNode={}", btcNode.toString());
}
} else {
try {
// We use DnsLookupTor to not leak with DNS lookup
// Blocking call. takes about 600 ms ;-(
InetSocketAddress address = new InetSocketAddress(DnsLookupTor.lookup(socks5Proxy, btcNode.getHostNameOrAddress()), btcNode.getPort());
log.info("We add a clear net node (tor is used) with InetAddress={}, btcNode={}", address.getAddress(), btcNode);
peerAddressList.add(new PeerAddress(address.getAddress(), address.getPort()));
} catch (Exception e) {
log.warn("Dns lookup failed for btcNode: {}", btcNode);
}
}
} else {
// We don't use Tor for BitcoinJ
// onion addresses are not supported
// We connect to onion nodes only in case we use Tor for BitcoinJ (default) to avoid privacy leaks at
// exit nodes with bloom filters.
if (useTorForBitcoinJ) {
btcNodeList.stream()
.filter(BitcoinNodes.BtcNode::hasOnionAddress)
.forEach(btcNode -> {
// no DNS lookup for onion addresses
log.info("We add a onion node. btcNode={}", btcNode);
final String onionAddress = btcNode.getOnionAddress();
try {
if (!btcNode.isHiddenService()) {
InetSocketAddress address = new InetSocketAddress(btcNode.getHostNameOrAddress(), btcNode.getPort());
log.info("We add a clear net node (no tor is used) with host={}, btcNode.getPort()={}", btcNode.getHostNameOrAddress(), btcNode.getPort());
peerAddressList.add(new PeerAddress(address.getAddress(), address.getPort()));
} else {
log.warn("Onion addresses are only supported when using Tor with BitcoinJ. Ignore btcNode {}", btcNode);
}
// OnionCat.onionHostToInetAddress converts onion to ipv6 representation
// inetAddress is not used but required for wallet persistence. Throws nullPointer if not set.
final InetAddress inetAddress = OnionCat.onionHostToInetAddress(onionAddress);
final PeerAddress peerAddress = new PeerAddress(onionAddress, btcNode.getPort());
peerAddress.setAddr(inetAddress);
peerAddressList.add(peerAddress);
} catch (UnknownHostException e) {
log.error("OnionCat.onionHostToInetAddress() failed with btcNode={}, error={}", btcNode.toString(), e.toString());
e.printStackTrace();
}
});
} else {
btcNodeList.stream()
.filter(BitcoinNodes.BtcNode::hasClearNetAddress)
.forEach(btcNode -> {
try {
InetSocketAddress address = new InetSocketAddress(btcNode.getHostNameOrAddress(), btcNode.getPort());
log.info("We add a clear net node (no tor is used) with host={}, btcNode.getPort()={}", btcNode.getHostNameOrAddress(), btcNode.getPort());
peerAddressList.add(new PeerAddress(address.getAddress(), address.getPort()));
} catch (Throwable t) {
log.warn("Failed to create InetSocketAddress from btcNode {}", btcNode);
}
}
}
);
});
}
if (!peerAddressList.isEmpty()) {
final PeerAddress[] peerAddresses = peerAddressList.toArray(new PeerAddress[peerAddressList.size()]);

View file

@ -13,7 +13,6 @@ import org.apache.commons.lang3.StringUtils;
import javax.annotation.Nullable;
import javax.inject.Inject;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
@ -24,8 +23,6 @@ public class CoreSeedNodesRepository implements SeedNodesRepository {
@Getter
private final Set<NodeAddress> seedNodeAddresses;
@Getter
private final Set<NodeAddress> seedNodeAddressesOldVersions;
@Inject
public CoreSeedNodesRepository(BisqEnvironment bisqEnvironment,
@ -35,27 +32,17 @@ public class CoreSeedNodesRepository implements SeedNodesRepository {
@Nullable @Named(NetworkOptionKeys.SEED_NODES_KEY) String seedNodes) {
List<String> bannedNodes = bisqEnvironment.getBannedSeedNodes();
Set<NodeAddress> nodeAddresses;
Set<NodeAddress> nodeAddressesOldVersions;
if (seedNodes != null && !seedNodes.isEmpty()) {
nodeAddresses = Arrays.asList(StringUtils.deleteWhitespace(seedNodes).split(","))
.stream()
.map(NodeAddress::new)
.collect(Collectors.toSet());
nodeAddressesOldVersions = new HashSet<>();
} else {
nodeAddresses = useLocalhostForP2P ? localhostSeedNodeAddresses : torSeedNodeAddresses;
nodeAddresses = nodeAddresses.stream()
.filter(e -> String.valueOf(e.getPort()).endsWith("0" + String.valueOf(networkId)))
.collect(Collectors.toSet());
if (!useLocalhostForP2P) {
nodeAddressesOldVersions = torSeedNodeAddressesOldVersions.stream()
.filter(e -> String.valueOf(e.getPort()).endsWith("0" + String.valueOf(networkId)))
.collect(Collectors.toSet());
} else {
nodeAddressesOldVersions = new HashSet<>();
}
}
seedNodeAddresses = nodeAddresses.stream()
@ -67,11 +54,6 @@ public class CoreSeedNodesRepository implements SeedNodesRepository {
log.info("seedNodeAddresses={}", seedNodeAddresses);
else
log.warn("We received banned seed nodes={}, seedNodeAddresses={}", bannedNodes, seedNodeAddresses);
seedNodeAddressesOldVersions = nodeAddressesOldVersions.stream()
.filter(e -> myAddress == null || myAddress.isEmpty() || !e.getFullAddress().equals(myAddress))
.filter(e -> bannedNodes == null || !bannedNodes.contains(e.getHostName()))
.collect(Collectors.toSet());
}
public String getOperator(NodeAddress nodeAddress) {
@ -83,7 +65,7 @@ public class CoreSeedNodesRepository implements SeedNodesRepository {
case "s67qglwhkgkyvr74.onion:8000":
return "@emzy";
case "jhgcy2won7xnslrb.onion:8000":
return "@sqrrm";
return "@ManfredKarrer";
case "3f3cu2yw7u457ztq.onion:8000":
return "@ManfredKarrer";
case "723ljisnynbtdohi.onion:8000":
@ -106,7 +88,7 @@ public class CoreSeedNodesRepository implements SeedNodesRepository {
case "s67qglwhkgkyvr74.onion:8000":
return "@emzy";
case "jhgcy2won7xnslrb.onion:8000":
return "@sqrrm";
return "@ManfredKarrer";
case "3f3cu2yw7u457ztq.onion:8000":
return "@manfredkarrer";
case "723ljisnynbtdohi.onion:8000":
@ -120,15 +102,6 @@ public class CoreSeedNodesRepository implements SeedNodesRepository {
}
}
/* old nodes pre 0.6.0 (still running for 0.5.* versions */
private Set<NodeAddress> torSeedNodeAddressesOldVersions =
Sets.newHashSet(
new NodeAddress("3f3cu2yw7u457ztq.onion:8000"), // @ManfredKarrer
new NodeAddress("723ljisnynbtdohi.onion:8000"), // @ManfredKarrer
new NodeAddress("rm7b56wbrcczpjvl.onion:8000"), // @ManfredKarrer
new NodeAddress("fl3mmribyxgrv63c.onion:8000") // @ManfredKarrer
);
// Addresses are used if their port match the network id:
// - mainnet uses port 8000
// - testnet uses port 8001
@ -137,9 +110,13 @@ public class CoreSeedNodesRepository implements SeedNodesRepository {
private Set<NodeAddress> torSeedNodeAddresses = Sets.newHashSet(
// BTC mainnet
new NodeAddress("5quyxpxheyvzmb2d.onion:8000"), // @mrosseel
new NodeAddress("ef5qnzx6znifo3df.onion:8000"), // @ManfredKarrer
new NodeAddress("s67qglwhkgkyvr74.onion:8000"), // @emzy
new NodeAddress("jhgcy2won7xnslrb.onion:8000"), // @sqrrm
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
//TODO dev
// local dev

View file

@ -35,10 +35,10 @@ import java.util.stream.Collectors;
public class ProvidersRepository {
private static final String NODES = "http://xc3nh4juf2hshy7e.onion/, " + // @emzy
"http://ceaanhbvluug4we6.onion/, " +// @mrosseel
"http://44mgyoe2b6oqiytt.onion/, " +// @ManfredKarrer
"http://5bmpx76qllutpcyp.onion/, " +// @ManfredKarrer
"http://rb2l2qale2pqzjyo.onion/"; // @sqrrm
// Old nodes before v 0.6.0: "http://44mgyoe2b6oqiytt.onion/, http://5bmpx76qllutpcyp.onion/"; @ManfredKarrer
private final String providersFromProgramArgs;
private final boolean useLocalhostForP2P;

View file

@ -30,8 +30,6 @@ public interface SeedNodesRepository {
Set<NodeAddress> getSeedNodeAddresses();
Set<NodeAddress> getSeedNodeAddressesOldVersions();
String getOperator(NodeAddress nodeAddress);
String getSlackUser(NodeAddress nodeAddress);

View file

@ -102,12 +102,15 @@ public class MetricsByNodeAddressMap extends HashMap<NodeAddress, Metrics> {
"<th align=\"left\">Num requests</th>" +
"<th align=\"left\">Num errors</th>" +
"<th align=\"left\">Last error message</th>" +
"<th align=\"left\">Duration average</th>" +
"<th align=\"left\">RRT average</th>" +
"<th align=\"left\">Last data</th>" +
"<th align=\"left\">Data deviation last request</th>" +
"</tr>");
StringBuilder sb = new StringBuilder();
sb.append("Seed nodes in error:" + totalErrors);
sb.append("\nLast check started at: " + time);
entryList.stream().forEach(e -> {
final List<Long> allDurations = e.getValue().getRequestDurations();
final String allDurationsString = allDurations.stream().map(Object::toString).collect(Collectors.joining("<br/>"));
@ -120,7 +123,16 @@ public class MetricsByNodeAddressMap extends HashMap<NodeAddress, Metrics> {
final List<String> errorMessages = e.getValue().getErrorMessages();
final int numErrors = (int) errorMessages.stream().filter(s -> !s.isEmpty()).count();
int numRequests = allDurations.size();
final String lastErrorMsg = numErrors > 0 ? errorMessages.get(errorMessages.size() - 1) : "";
String lastErrorMsg = "";
int lastIndexOfError = -1;
for (int i = 0; i < errorMessages.size(); i++) {
final String msg = errorMessages.get(i);
if (!msg.isEmpty()) {
lastIndexOfError = i;
lastErrorMsg = "Error at request " + lastIndexOfError + ":" + msg;
}
}
// String lastErrorMsg = numErrors > 0 ? errorMessages.get(errorMessages.size() - 1) : "";
final List<Map<String, Integer>> allReceivedData = e.getValue().getReceivedObjectsList();
Map<String, Integer> lastReceivedData = !allReceivedData.isEmpty() ? allReceivedData.get(allReceivedData.size() - 1) : new HashMap<>();
final String lastReceivedDataString = lastReceivedData.entrySet().stream().map(Object::toString).collect(Collectors.joining("<br/>"));
@ -131,10 +143,10 @@ public class MetricsByNodeAddressMap extends HashMap<NodeAddress, Metrics> {
.append("\nNum requests: ").append(numRequests)
.append("\nNum errors: ").append(numErrors)
.append("\nLast error message: ").append(lastErrorMsg)
.append("\nDuration average: ").append(durationAverage)
.append("\nRRT average: ").append(durationAverage)
.append("\nLast data: ").append(lastReceivedDataString);
String colorNumErrors = lastErrorMsg.isEmpty() ? "black" : "red";
String colorNumErrors = lastIndexOfError == numErrors ? "black" : "red";
String colorDurationAverage = durationAverage < 30 ? "black" : "red";
html.append("<tr>")
.append("<td>").append("<font color=\"" + colorNumErrors + "\">" + operator + "</font> ").append("</td>")
@ -167,7 +179,7 @@ public class MetricsByNodeAddressMap extends HashMap<NodeAddress, Metrics> {
if (slackApi != null)
slackApi.call(new SlackMessage("Warning: " + nodeAddress.getFullAddress(),
"<" + seedNodesRepository.getSlackUser(nodeAddress) + ">" + " Your seed node delivers diverging results for " + dataItem + ". " +
"Please check the monitoring status page at http://178.62.249.232:8080/"));
"Please check the monitoring status page at http://seedmonitor.0-2-1.net:8080/"));
}
});
sb.append("\nDuration all requests: ").append(allDurationsString)

View file

@ -71,7 +71,6 @@ public class MonitorRequestManager implements ConnectionListener {
this.networkNode.addConnectionListener(this);
seedNodeAddresses = new HashSet<>(seedNodesRepository.getSeedNodeAddresses());
seedNodeAddresses.addAll(seedNodesRepository.getSeedNodeAddressesOldVersions());
seedNodeAddresses.stream().forEach(nodeAddress -> metricsByNodeAddressMap.put(nodeAddress, new Metrics()));
}