Shut down connection after response received

Various improvements...
This commit is contained in:
chimp1984 2020-10-18 19:58:25 -05:00
parent 1b83083ade
commit 7768e58b98
No known key found for this signature in database
GPG Key ID: 9801B4EC591F90E3
6 changed files with 343 additions and 236 deletions

View File

@ -81,6 +81,9 @@ public class GetInventoryRequester implements MessageListener, ConnectionListene
GetInventoryResponse getInventoryResponse = (GetInventoryResponse) networkEnvelope;
resultHandler.accept(getInventoryResponse.getInventory());
shutDown();
// We shut down our connection after work as our node is not helpful for the network.
connection.shutDown(CloseConnectionReason.CLOSE_REQUESTED_BY_PEER);
}
});
}

View File

@ -29,8 +29,6 @@ import bisq.network.p2p.network.NetworkNode;
import bisq.network.p2p.network.SetupListener;
import bisq.common.UserThread;
import bisq.common.app.Capabilities;
import bisq.common.app.Capability;
import bisq.common.config.BaseCurrencyNetwork;
import bisq.common.file.JsonFileManager;
import bisq.common.util.Utilities;
@ -40,7 +38,6 @@ import java.time.Clock;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@ -49,15 +46,18 @@ import java.util.stream.Collectors;
import lombok.extern.slf4j.Slf4j;
import static com.google.common.base.Preconditions.checkArgument;
@Slf4j
public class InventoryMonitor {
public class InventoryMonitor implements SetupListener {
private final Map<NodeAddress, JsonFileManager> jsonFileManagerByNodeAddress = new HashMap<>();
private final Map<NodeAddress, List<RequestInfo>> requestInfoListByNode = new HashMap<>();
private final File appDir;
private final boolean useLocalhostForP2P;
private final int intervalSec;
private final NetworkNode networkNode;
private final GetInventoryRequestManager getInventoryRequestManager;
private ArrayList<NodeAddress> seedNodes;
private InventoryWebServer inventoryWebServer;
private int requestCounter = 0;
public InventoryMonitor(File appDir,
@ -65,10 +65,12 @@ public class InventoryMonitor {
BaseCurrencyNetwork network,
int intervalSec,
int port) {
this.appDir = appDir;
this.useLocalhostForP2P = useLocalhostForP2P;
this.intervalSec = intervalSec;
setupCapabilities();
networkNode = getNetworkNode(appDir);
getInventoryRequestManager = new GetInventoryRequestManager(networkNode);
//TODO until we use all seeds we use our custom seed node file which includes only those which have updated to our branch
// Once all seeds are updated we can remove that resource file and prefix
@ -76,104 +78,38 @@ public class InventoryMonitor {
String networkName = network.name().toLowerCase();
String fileName = network.isMainnet() ? "inv_" + networkName : networkName;
DefaultSeedNodeRepository.readSeedNodePropertyFile(fileName)
.ifPresent(seedNodeFile -> {
List<NodeAddress> seedNodes = new ArrayList<>(DefaultSeedNodeRepository.getSeedNodeAddressesFromPropertyFile(fileName));
File jsonDir = new File(appDir, "json");
if (!jsonDir.exists() && !jsonDir.mkdir()) {
log.warn("make jsonDir failed");
}
seedNodes.forEach(nodeAddress -> {
JsonFileManager jsonFileManager = new JsonFileManager(new File(jsonDir, getShortAddress(nodeAddress, useLocalhostForP2P)));
jsonFileManagerByNodeAddress.put(nodeAddress, jsonFileManager);
});
NetworkNode networkNode = getNetworkNode(appDir);
GetInventoryRequestManager getInventoryRequestManager = new GetInventoryRequestManager(networkNode);
InventoryWebServer inventoryWebServer = new InventoryWebServer(port, seedNodes, seedNodeFile);
networkNode.start(new SetupListener() {
@Override
public void onTorNodeReady() {
startRequests(inventoryWebServer, getInventoryRequestManager, seedNodes);
}
@Override
public void onHiddenServicePublished() {
}
@Override
public void onSetupFailed(Throwable throwable) {
}
@Override
public void onRequestCustomBridges() {
}
});
.ifPresent(bufferedReader -> {
seedNodes = new ArrayList<>(DefaultSeedNodeRepository.getSeedNodeAddressesFromPropertyFile(fileName));
addJsonFileManagers(seedNodes);
inventoryWebServer = new InventoryWebServer(port, seedNodes, bufferedReader);
networkNode.start(this);
});
}
@Override
public void onTorNodeReady() {
UserThread.runPeriodically(this::requestAllSeeds, intervalSec);
requestAllSeeds();
}
@Override
public void onHiddenServicePublished() {
}
@Override
public void onSetupFailed(Throwable throwable) {
}
@Override
public void onRequestCustomBridges() {
}
public void shutDown() {
jsonFileManagerByNodeAddress.values().forEach(JsonFileManager::shutDown);
inventoryWebServer.shutDown();
}
private NetworkNode getNetworkNode(File appDir) {
File torDir = new File(appDir, "tor");
CoreNetworkProtoResolver networkProtoResolver = new CoreNetworkProtoResolver(Clock.systemDefaultZone());
return new NetworkNodeProvider(networkProtoResolver,
ArrayList::new,
useLocalhostForP2P,
9999,
torDir,
null,
"",
-1,
"",
null,
false,
false).get();
}
protected void setupCapabilities() {
Capabilities.app.addAll(
Capability.TRADE_STATISTICS,
Capability.TRADE_STATISTICS_2,
Capability.ACCOUNT_AGE_WITNESS,
Capability.ACK_MSG,
Capability.PROPOSAL,
Capability.BLIND_VOTE,
Capability.DAO_STATE,
Capability.BUNDLE_OF_ENVELOPES,
Capability.MEDIATION,
Capability.SIGNED_ACCOUNT_AGE_WITNESS,
Capability.REFUND_AGENT,
Capability.TRADE_STATISTICS_HASH_UPDATE,
Capability.NO_ADDRESS_PRE_FIX,
Capability.TRADE_STATISTICS_3,
Capability.RECEIVE_BSQ_BLOCK
);
}
private String getShortAddress(NodeAddress nodeAddress, boolean useLocalhostForP2P) {
return useLocalhostForP2P ?
nodeAddress.getFullAddress().replace(":", "_") :
nodeAddress.getFullAddress().substring(0, 10);
}
private void startRequests(InventoryWebServer inventoryWebServer,
GetInventoryRequestManager getInventoryRequestManager,
List<NodeAddress> seedNodes) {
UserThread.runPeriodically(() ->
requestAllSeeds(inventoryWebServer, getInventoryRequestManager, seedNodes),
intervalSec);
requestAllSeeds(inventoryWebServer, getInventoryRequestManager, seedNodes);
}
private void requestAllSeeds(InventoryWebServer inventoryWebServer,
GetInventoryRequestManager getInventoryRequestManager,
List<NodeAddress> seedNodes) {
private void requestAllSeeds() {
requestCounter++;
seedNodes.forEach(nodeAddress -> {
RequestInfo requestInfo = new RequestInfo(System.currentTimeMillis());
@ -196,7 +132,7 @@ public class InventoryMonitor {
.filter(list -> !list.isEmpty())
.map(list -> list.get(list.size() - 1))
.collect(Collectors.toSet());
Map<InventoryItem, Double> averageValues = getAverageValues(requestInfoSetOfOtherNodes);
Map<InventoryItem, Double> averageValues = InventoryUtil.getAverageValues(requestInfoSetOfOtherNodes);
inventoryWebServer.onNewRequestInfo(requestInfoListByNode, averageValues, requestCounter);
@ -212,51 +148,37 @@ public class InventoryMonitor {
});
}
private Map<InventoryItem, Double> getAverageValues(Set<RequestInfo> requestInfoSetOfOtherNodes) {
Map<InventoryItem, Double> averageValuesPerItem = new HashMap<>();
Arrays.asList(InventoryItem.values()).forEach(inventoryItem -> {
if (inventoryItem.getType().equals(Integer.class)) {
averageValuesPerItem.put(inventoryItem, getAverageFromIntegerValues(requestInfoSetOfOtherNodes, inventoryItem));
} else if (inventoryItem.getType().equals(Long.class)) {
averageValuesPerItem.put(inventoryItem, getAverageFromLongValues(requestInfoSetOfOtherNodes, inventoryItem));
} else if (inventoryItem.getType().equals(Double.class)) {
averageValuesPerItem.put(inventoryItem, getAverageFromDoubleValues(requestInfoSetOfOtherNodes, inventoryItem));
}
// If type of value is String we ignore it
private void addJsonFileManagers(List<NodeAddress> seedNodes) {
File jsonDir = new File(appDir, "json");
if (!jsonDir.exists() && !jsonDir.mkdir()) {
log.warn("make jsonDir failed");
}
seedNodes.forEach(nodeAddress -> {
JsonFileManager jsonFileManager = new JsonFileManager(new File(jsonDir, getShortAddress(nodeAddress, useLocalhostForP2P)));
jsonFileManagerByNodeAddress.put(nodeAddress, jsonFileManager);
});
return averageValuesPerItem;
}
private double getAverageFromIntegerValues(Set<RequestInfo> requestInfoSetOfOtherNodes,
InventoryItem inventoryItem) {
checkArgument(inventoryItem.getType().equals(Integer.class));
return requestInfoSetOfOtherNodes.stream()
.map(RequestInfo::getInventory)
.filter(inventory -> inventory.containsKey(inventoryItem))
.mapToInt(inventory -> Integer.parseInt(inventory.get(inventoryItem)))
.average()
.orElse(0d);
private NetworkNode getNetworkNode(File appDir) {
File torDir = new File(appDir, "tor");
CoreNetworkProtoResolver networkProtoResolver = new CoreNetworkProtoResolver(Clock.systemDefaultZone());
return new NetworkNodeProvider(networkProtoResolver,
ArrayList::new,
useLocalhostForP2P,
9999,
torDir,
null,
"",
-1,
"",
null,
false,
false).get();
}
private double getAverageFromLongValues(Set<RequestInfo> requestInfoSetOfOtherNodes,
InventoryItem inventoryItem) {
checkArgument(inventoryItem.getType().equals(Long.class));
return requestInfoSetOfOtherNodes.stream()
.map(RequestInfo::getInventory)
.filter(inventory -> inventory.containsKey(inventoryItem))
.mapToLong(inventory -> Long.parseLong(inventory.get(inventoryItem)))
.average()
.orElse(0d);
}
private double getAverageFromDoubleValues(Set<RequestInfo> requestInfoSetOfOtherNodes,
InventoryItem inventoryItem) {
checkArgument(inventoryItem.getType().equals(Double.class));
return requestInfoSetOfOtherNodes.stream()
.map(RequestInfo::getInventory)
.filter(inventory -> inventory.containsKey(inventoryItem))
.mapToDouble(inventory -> Double.parseDouble((inventory.get(inventoryItem))))
.average()
.orElse(0d);
private String getShortAddress(NodeAddress nodeAddress, boolean useLocalhostForP2P) {
return useLocalhostForP2P ?
nodeAddress.getFullAddress().replace(":", "_") :
nodeAddress.getFullAddress().substring(0, 10);
}
}

View File

@ -21,6 +21,7 @@ package bisq.inventory;
import bisq.core.locale.Res;
import bisq.common.UserThread;
import bisq.common.app.AsciiLogo;
import bisq.common.app.Log;
import bisq.common.app.Version;
import bisq.common.config.BaseCurrencyNetwork;
@ -51,7 +52,8 @@ public class InventoryMonitorMain {
// prog args for regtest: 10 1 BTC_REGTEST
public static void main(String[] args) {
int intervalSec = 600;
// Default values
int intervalSec = 300;
boolean useLocalhostForP2P = false;
BaseCurrencyNetwork network = BaseCurrencyNetwork.BTC_MAINNET;
int port = 80;
@ -69,16 +71,27 @@ public class InventoryMonitorMain {
port = Integer.parseInt(args[3]);
}
String appName = "bisq-InventoryMonitor-" + network;
String appName = "bisq-InventoryMonitor-" + network + "-" + intervalSec;
File appDir = new File(Utilities.getUserDataDir(), appName);
if (!appDir.exists() && !appDir.mkdir()) {
log.warn("make appDir failed");
}
inventoryMonitor = new InventoryMonitor(appDir, useLocalhostForP2P, network, intervalSec, port);
setup(network, appDir);
}
private static void setup(BaseCurrencyNetwork network, File appDir) {
AsciiLogo.showAsciiLogo();
String logPath = Paths.get(appDir.getPath(), "bisq").toString();
Log.setup(logPath);
Log.setLevel(Level.INFO);
Version.setBaseCryptoNetworkId(network.ordinal());
Res.setup();
inventoryMonitor = new InventoryMonitor(appDir, useLocalhostForP2P, network, intervalSec, port);
Res.setup(); // Used for some formatting in the webserver
// We do not set any capabilities as we don't want to receive any network data beside our response.
// We also do not use capabilities for the request/response messages as we only connect to seeds nodes and
ThreadFactory threadFactory = new ThreadFactoryBuilder()
.setNameFormat(inventoryMonitor.getClass().getSimpleName())

View File

@ -0,0 +1,124 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
package bisq.inventory;
import bisq.core.network.p2p.inventory.DeviationSeverity;
import bisq.core.network.p2p.inventory.InventoryItem;
import bisq.network.p2p.NodeAddress;
import bisq.common.util.Tuple2;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import static com.google.common.base.Preconditions.checkArgument;
public class InventoryUtil {
public static Map<InventoryItem, Double> getAverageValues(Set<RequestInfo> requestInfoSetOfOtherNodes) {
Map<InventoryItem, Double> averageValuesPerItem = new HashMap<>();
Arrays.asList(InventoryItem.values()).forEach(inventoryItem -> {
if (inventoryItem.getType().equals(Integer.class)) {
averageValuesPerItem.put(inventoryItem, getAverageFromIntegerValues(requestInfoSetOfOtherNodes, inventoryItem));
} else if (inventoryItem.getType().equals(Long.class)) {
averageValuesPerItem.put(inventoryItem, getAverageFromLongValues(requestInfoSetOfOtherNodes, inventoryItem));
} else if (inventoryItem.getType().equals(Double.class)) {
averageValuesPerItem.put(inventoryItem, getAverageFromDoubleValues(requestInfoSetOfOtherNodes, inventoryItem));
}
// If type of value is String we ignore it
});
return averageValuesPerItem;
}
public static double getAverageFromIntegerValues(Set<RequestInfo> requestInfoSetOfOtherNodes,
InventoryItem inventoryItem) {
checkArgument(inventoryItem.getType().equals(Integer.class));
return requestInfoSetOfOtherNodes.stream()
.map(RequestInfo::getInventory)
.filter(inventory -> inventory.containsKey(inventoryItem))
.mapToInt(inventory -> Integer.parseInt(inventory.get(inventoryItem)))
.average()
.orElse(0d);
}
public static double getAverageFromLongValues(Set<RequestInfo> requestInfoSetOfOtherNodes,
InventoryItem inventoryItem) {
checkArgument(inventoryItem.getType().equals(Long.class));
return requestInfoSetOfOtherNodes.stream()
.map(RequestInfo::getInventory)
.filter(inventory -> inventory.containsKey(inventoryItem))
.mapToLong(inventory -> Long.parseLong(inventory.get(inventoryItem)))
.average()
.orElse(0d);
}
public static double getAverageFromDoubleValues(Set<RequestInfo> requestInfoSetOfOtherNodes,
InventoryItem inventoryItem) {
checkArgument(inventoryItem.getType().equals(Double.class));
return requestInfoSetOfOtherNodes.stream()
.map(RequestInfo::getInventory)
.filter(inventory -> inventory.containsKey(inventoryItem))
.mapToDouble(inventory -> Double.parseDouble((inventory.get(inventoryItem))))
.average()
.orElse(0d);
}
public static DeviationSeverity getDeviationSeverityForHash(Map<NodeAddress, List<RequestInfo>> map,
String daoStateChainHeightAsString,
RequestInfo requestInfo,
InventoryItem daoStateHash) {
DeviationSeverity deviationSeverity = DeviationSeverity.OK;
Map<String, Integer> sameHashesPerHash = new HashMap<>();
map.values().stream()
.filter(list -> !list.isEmpty())
.map(list -> list.get(list.size() - 1)) // We use last item only
.map(RequestInfo::getInventory)
.filter(e -> e.get(InventoryItem.daoStateChainHeight).equals(daoStateChainHeightAsString))
.map(e -> e.get(daoStateHash))
.forEach(e -> {
sameHashesPerHash.putIfAbsent(e, 0);
int prev = sameHashesPerHash.get(e);
sameHashesPerHash.put(e, prev + 1);
});
if (sameHashesPerHash.size() > 1) {
List<Tuple2<String, Integer>> sameHashesPerHashList = new ArrayList<>();
sameHashesPerHash.forEach((key, value) -> sameHashesPerHashList.add(new Tuple2<>(key, value)));
sameHashesPerHashList.sort(Comparator.comparing(o -> o.second));
Collections.reverse(sameHashesPerHashList);
// It could be that first and any following list entry has same number of hashes, but we ignore that as
// it is reason enough to alert the operators in case not all hashes are the same.
if (sameHashesPerHashList.get(0).first.equals(requestInfo.getInventory().get(daoStateHash))) {
// We are in the majority group.
// We also set a warning to make sure the operators act quickly and to check if there are
// more severe issues.
deviationSeverity = DeviationSeverity.WARN;
} else {
deviationSeverity = DeviationSeverity.ALERT;
}
}
return deviationSeverity;
}
}

View File

@ -57,16 +57,6 @@ public class InventoryWebServer {
this.seedNodes = seedNodes;
setupOperatorMap(seedNodeFile);
setupServer(port);
}
public void onNewRequestInfo(Map<NodeAddress, List<RequestInfo>> requestInfoListByNode,
Map<InventoryItem, Double> averageValues, int requestCounter) {
this.requestCounter = requestCounter;
html = getHtml(requestInfoListByNode, averageValues);
}
private void setupServer(int port) {
Spark.port(port);
Spark.get("/", (req, res) -> {
log.info("Incoming request from: {}", req.userAgent());
@ -74,19 +64,19 @@ public class InventoryWebServer {
});
}
private void setupOperatorMap(BufferedReader seedNodeFile) {
seedNodeFile.lines().forEach(line -> {
if (!line.startsWith("#")) {
String[] strings = line.split(" \\(@");
String node = strings.length > 0 ? strings[0] : "n/a";
String operator = strings.length > 1 ? strings[1].replace(")", "") : "n/a";
operatorByNodeAddress.put(node, operator);
}
});
public void onNewRequestInfo(Map<NodeAddress, List<RequestInfo>> requestInfoListByNode,
Map<InventoryItem, Double> averageValues,
int requestCounter) {
this.requestCounter = requestCounter;
html = generateHtml(requestInfoListByNode, averageValues);
}
private String getHtml(Map<NodeAddress, List<RequestInfo>> map,
Map<InventoryItem, Double> averageValues) {
public void shutDown() {
Spark.stop();
}
private String generateHtml(Map<NodeAddress, List<RequestInfo>> map,
Map<InventoryItem, Double> averageValues) {
StringBuilder html = new StringBuilder();
html.append("<html>" +
"<head><style>table, th, td {border: 1px solid black;}</style></head>" +
@ -110,7 +100,7 @@ public class InventoryWebServer {
.append("<td>").append(getSeedNodeInfo(seedNode, requestInfo, averageValues)).append("</td>")
.append("<td>").append(getRequestInfo(requestInfo, numRequests)).append("</td>")
.append("<td>").append(getDataInfo(requestInfo, averageValues)).append("</td>")
.append("<td>").append(getDaoInfo(requestInfo, averageValues)).append("</td>")
.append("<td>").append(getDaoInfo(requestInfo, averageValues, map)).append("</td>")
.append("<td>").append(getNetworkInfo(requestInfo, averageValues)).append("</td>");
html.append("</tr>");
} else {
@ -128,7 +118,6 @@ public class InventoryWebServer {
return html.toString();
}
private String getSeedNodeInfo(NodeAddress nodeAddress,
@Nullable RequestInfo requestInfo,
Map<InventoryItem, Double> averageValues) {
@ -144,32 +133,32 @@ public class InventoryWebServer {
addInventoryItem("Version: ", requestInfo, sb, InventoryItem.version);
addInventoryItem("Memory used: ", requestInfo, averageValues, sb, InventoryItem.usedMemory,
value -> Utilities.readableFileSize(Long.parseLong(value)));
addInventoryItem("Node started at: ",
String jvmStartTimeString = addInventoryItem("Node started at: ",
requestInfo,
null,
sb,
InventoryItem.jvmStartTime,
value -> new Date(Long.parseLong(value)).toString());
long jvmStartTime = Long.parseLong(requestInfo.getInventory().get(InventoryItem.jvmStartTime));
String duration = FormattingUtils.formatDurationAsWords(System.currentTimeMillis() - jvmStartTime, true, true);
String duration = FormattingUtils.formatDurationAsWords(
System.currentTimeMillis() - Long.parseLong(jvmStartTimeString),
true, true);
sb.append("Run duration: ").append(duration).append("<br/>");
}
return sb.toString();
}
private String getRequestInfo(RequestInfo last, int numRequests) {
private String getRequestInfo(RequestInfo requestInfo, int numRequests) {
StringBuilder sb = new StringBuilder();
Date requestStartTime = new Date(last.getRequestStartTime());
Date requestStartTime = new Date(requestInfo.getRequestStartTime());
sb.append("Requested at: ").append(requestStartTime).append("<br/>");
Date responseTime = new Date(last.getResponseTime());
Date responseTime = new Date(requestInfo.getResponseTime());
sb.append("Response received at: ").append(responseTime).append("<br/>");
long rrt = last.getResponseTime() - last.getRequestStartTime();
long rrt = requestInfo.getResponseTime() - requestInfo.getRequestStartTime();
DeviationSeverity rrtDeviationSeverity = DeviationSeverity.OK;
if (rrt > 20_000) {
rrtDeviationSeverity = DeviationSeverity.ALERT;
@ -184,7 +173,7 @@ public class InventoryWebServer {
sb.append("Number of requests: ").append(getColorTagByDeviationSeverity(DeviationSeverity.OK))
.append(numRequests).append(CLOSE_TAG);
String errorMessage = last.getErrorMessage();
String errorMessage = requestInfo.getErrorMessage();
rrtDeviationSeverity = errorMessage == null || errorMessage.isEmpty() ?
DeviationSeverity.OK :
DeviationSeverity.WARN;
@ -194,99 +183,141 @@ public class InventoryWebServer {
return sb.toString();
}
private String getDataInfo(RequestInfo last,
private String getDataInfo(RequestInfo requestInfo,
Map<InventoryItem, Double> averageValues) {
StringBuilder sb = new StringBuilder();
addInventoryItem(last, averageValues, sb, InventoryItem.OfferPayload);
addInventoryItem(last, averageValues, sb, InventoryItem.MailboxStoragePayload);
addInventoryItem(last, averageValues, sb, InventoryItem.TradeStatistics3);
addInventoryItem(last, averageValues, sb, InventoryItem.Alert);
addInventoryItem(last, averageValues, sb, InventoryItem.Filter);
addInventoryItem(last, averageValues, sb, InventoryItem.Mediator);
addInventoryItem(last, averageValues, sb, InventoryItem.RefundAgent);
addInventoryItem(last, averageValues, sb, InventoryItem.AccountAgeWitness);
addInventoryItem(last, averageValues, sb, InventoryItem.SignedWitness);
addInventoryItem(requestInfo, averageValues, sb, InventoryItem.OfferPayload);
addInventoryItem(requestInfo, averageValues, sb, InventoryItem.MailboxStoragePayload);
addInventoryItem(requestInfo, averageValues, sb, InventoryItem.TradeStatistics3);
addInventoryItem(requestInfo, averageValues, sb, InventoryItem.Alert);
addInventoryItem(requestInfo, averageValues, sb, InventoryItem.Filter);
addInventoryItem(requestInfo, averageValues, sb, InventoryItem.Mediator);
addInventoryItem(requestInfo, averageValues, sb, InventoryItem.RefundAgent);
addInventoryItem(requestInfo, averageValues, sb, InventoryItem.AccountAgeWitness);
addInventoryItem(requestInfo, averageValues, sb, InventoryItem.SignedWitness);
return sb.toString();
}
private String getDaoInfo(RequestInfo last,
Map<InventoryItem, Double> averageValues) {
private String getDaoInfo(RequestInfo requestInfo,
Map<InventoryItem, Double> averageValues,
Map<NodeAddress, List<RequestInfo>> map) {
StringBuilder sb = new StringBuilder();
addInventoryItem("Number of BSQ blocks: ", last, averageValues, sb, InventoryItem.numBsqBlocks);
addInventoryItem(last, averageValues, sb, InventoryItem.TempProposalPayload);
addInventoryItem(last, averageValues, sb, InventoryItem.ProposalPayload);
addInventoryItem(last, averageValues, sb, InventoryItem.BlindVotePayload);
addInventoryItem("DAO state block height: ", last, averageValues, sb, InventoryItem.daoStateChainHeight);
addInventoryItem("DAO state hash: ", last, sb, InventoryItem.daoStateHash);
addInventoryItem("Proposal state hash: ", last, sb, InventoryItem.proposalHash);
addInventoryItem("Blind vote state hash: ", last, sb, InventoryItem.blindVoteHash);
addInventoryItem("Number of BSQ blocks: ", requestInfo, averageValues, sb, InventoryItem.numBsqBlocks);
addInventoryItem(requestInfo, averageValues, sb, InventoryItem.TempProposalPayload);
addInventoryItem(requestInfo, averageValues, sb, InventoryItem.ProposalPayload);
addInventoryItem(requestInfo, averageValues, sb, InventoryItem.BlindVotePayload);
String daoStateChainHeightAsString = addInventoryItem("DAO state block height: ", requestInfo,
averageValues, sb, InventoryItem.daoStateChainHeight);
DeviationSeverity daoStateHashDeviationSeverity = InventoryUtil.getDeviationSeverityForHash(map,
daoStateChainHeightAsString,
requestInfo,
InventoryItem.daoStateHash);
addInventoryItem("DAO state hash: ", requestInfo, null, sb,
InventoryItem.daoStateHash, null, daoStateHashDeviationSeverity);
// The hash for proposal changes only at first block of blind vote phase but as we do not want to initialize the
// dao domain we cannot check that. But we also don't need that as we can just compare that all hashes at all
// blocks from all seeds are the same. Same for blindVoteHash.
DeviationSeverity proposalHashDeviationSeverity = InventoryUtil.getDeviationSeverityForHash(map,
daoStateChainHeightAsString,
requestInfo,
InventoryItem.proposalHash);
addInventoryItem("Proposal state hash: ", requestInfo, null, sb,
InventoryItem.proposalHash, null, proposalHashDeviationSeverity);
DeviationSeverity blindVoteHashDeviationSeverity = InventoryUtil.getDeviationSeverityForHash(map,
daoStateChainHeightAsString,
requestInfo,
InventoryItem.blindVoteHash);
addInventoryItem("Blind vote state hash: ", requestInfo, null, sb,
InventoryItem.blindVoteHash, null, blindVoteHashDeviationSeverity);
return sb.toString();
}
private String getNetworkInfo(RequestInfo last,
private String getNetworkInfo(RequestInfo requestInfo,
Map<InventoryItem, Double> averageValues) {
StringBuilder sb = new StringBuilder();
addInventoryItem("Max. connections: ", last, averageValues, sb, InventoryItem.maxConnections);
addInventoryItem("Number of connections: ", last, averageValues, sb, InventoryItem.numConnections);
addInventoryItem("Max. connections: ", requestInfo, averageValues, sb, InventoryItem.maxConnections);
addInventoryItem("Number of connections: ", requestInfo, averageValues, sb, InventoryItem.numConnections);
addInventoryItem("Sent messages/sec: ", last, averageValues, sb, InventoryItem.sentMessagesPerSec,
addInventoryItem("Sent messages/sec: ", requestInfo, averageValues, sb, InventoryItem.sentMessagesPerSec,
value -> String.valueOf(MathUtils.roundDouble(Double.parseDouble(value), 2)));
addInventoryItem("Received messages/sec: ", last, averageValues, sb, InventoryItem.receivedMessagesPerSec,
addInventoryItem("Received messages/sec: ", requestInfo, averageValues, sb, InventoryItem.receivedMessagesPerSec,
value -> String.valueOf(MathUtils.roundDouble(Double.parseDouble(value), 2)));
addInventoryItem("Sent bytes/sec: ", last, averageValues, sb, InventoryItem.sentBytesPerSec,
addInventoryItem("Sent bytes/sec: ", requestInfo, averageValues, sb, InventoryItem.sentBytesPerSec,
value -> String.valueOf(MathUtils.roundDouble(Double.parseDouble(value), 2)));
addInventoryItem("Received bytes/sec: ", last, averageValues, sb, InventoryItem.receivedBytesPerSec,
addInventoryItem("Received bytes/sec: ", requestInfo, averageValues, sb, InventoryItem.receivedBytesPerSec,
value -> String.valueOf(MathUtils.roundDouble(Double.parseDouble(value), 2)));
addInventoryItem("Sent data: ", last, averageValues, sb, InventoryItem.sentBytes,
addInventoryItem("Sent data: ", requestInfo, averageValues, sb, InventoryItem.sentBytes,
value -> Utilities.readableFileSize(Long.parseLong(value)));
addInventoryItem("Received data: ", last, averageValues, sb, InventoryItem.receivedBytes,
addInventoryItem("Received data: ", requestInfo, averageValues, sb, InventoryItem.receivedBytes,
value -> Utilities.readableFileSize(Long.parseLong(value)));
return sb.toString();
}
private void addInventoryItem(RequestInfo requestInfo,
Map<InventoryItem, Double> averageValues,
StringBuilder sb,
InventoryItem inventoryItem) {
addInventoryItem("Number of " + inventoryItem.getKey() + ": ",
private String addInventoryItem(RequestInfo requestInfo,
Map<InventoryItem, Double> averageValues,
StringBuilder sb,
InventoryItem inventoryItem) {
return addInventoryItem("Number of " + inventoryItem.getKey() + ": ",
requestInfo,
averageValues,
sb,
inventoryItem);
}
private void addInventoryItem(String title,
RequestInfo requestInfo,
StringBuilder sb,
InventoryItem inventoryItem) {
addInventoryItem(title,
private String addInventoryItem(String title,
RequestInfo requestInfo,
StringBuilder sb,
InventoryItem inventoryItem) {
return addInventoryItem(title,
requestInfo,
null,
sb,
inventoryItem);
}
private void addInventoryItem(String title,
RequestInfo requestInfo,
@Nullable Map<InventoryItem, Double> averageValues,
StringBuilder sb,
InventoryItem inventoryItem) {
addInventoryItem(title,
private String addInventoryItem(String title,
RequestInfo requestInfo,
@Nullable Map<InventoryItem, Double> averageValues,
StringBuilder sb,
InventoryItem inventoryItem) {
return addInventoryItem(title,
requestInfo,
averageValues,
sb,
inventoryItem,
null,
null);
}
private void addInventoryItem(String title,
RequestInfo requestInfo,
@Nullable Map<InventoryItem, Double> averageValues,
StringBuilder sb,
InventoryItem inventoryItem,
@Nullable Function<String, String> formatter) {
String valueAsString;
private String addInventoryItem(String title,
RequestInfo requestInfo,
@Nullable Map<InventoryItem, Double> averageValues,
StringBuilder sb,
InventoryItem inventoryItem,
@Nullable Function<String, String> formatter) {
return addInventoryItem(title,
requestInfo,
averageValues,
sb,
inventoryItem,
formatter,
null);
}
private String addInventoryItem(String title,
RequestInfo requestInfo,
@Nullable Map<InventoryItem, Double> averageValues,
StringBuilder sb,
InventoryItem inventoryItem,
@Nullable Function<String, String> formatter,
@Nullable DeviationSeverity deviationSeverity) {
String valueAsString = null;
String displayString = "n/a";
String deviationAsString = "";
String colorTag = getColorTagByDeviationSeverity(DeviationSeverity.OK);
if (requestInfo.getInventory().containsKey(inventoryItem)) {
@ -311,15 +342,20 @@ public class InventoryWebServer {
}
}
if (deviationSeverity != null) {
colorTag = getColorTagByDeviationSeverity(deviationSeverity);
}
// We only do formatting if we have any value
if (formatter != null) {
valueAsString = formatter.apply(valueAsString);
displayString = formatter.apply(valueAsString);
} else {
displayString = valueAsString;
}
} else {
valueAsString = "n/a";
}
sb.append(title).append(colorTag).append(valueAsString).append(deviationAsString).append(CLOSE_TAG);
sb.append(title).append(colorTag).append(displayString).append(deviationAsString).append(CLOSE_TAG);
return valueAsString;
}
private String getColorTagByDeviationSeverity(DeviationSeverity deviationSeverity) {
@ -333,4 +369,15 @@ public class InventoryWebServer {
return "<font color=\"black\">";
}
}
private void setupOperatorMap(BufferedReader seedNodeFile) {
seedNodeFile.lines().forEach(line -> {
if (!line.startsWith("#")) {
String[] strings = line.split(" \\(@");
String node = strings.length > 0 ? strings[0] : "n/a";
String operator = strings.length > 1 ? strings[1].replace(")", "") : "n/a";
operatorByNodeAddress.put(node, operator);
}
});
}
}

View File

@ -10,5 +10,3 @@ s67qglwhkgkyvr74.onion:8000 (@emzy)
sn2bisqad7ncazupgbd3dcedqh5ptirgwofw63djwpdtftwhddo75oid.onion:8000 (@miker)
sn3bsq3evqkpshdmc3sbdxafkhfnk7ctop44jsxbxyys5ridsaw5abyd.onion:8000 (@miker)
sn4bsqpc7eb2ntvpsycxbzqt6fre72l4krp2fl5svphfh2eusrqtq3qd.onion:8000 (@miker)
5quyxpxheyvzmb2d.onion:8000 (@miker)
rm7b56wbrcczpjvl.onion:8000 (@miker)