From a925017e4becda784a35b7dfa90e4ed56db22509 Mon Sep 17 00:00:00 2001 From: HenrikJannsen Date: Tue, 29 Nov 2022 19:56:04 -0500 Subject: [PATCH 01/11] Rename readCommitHash to findCommitHash, make it static and return optional. Signed-off-by: HenrikJannsen --- common/src/main/java/bisq/common/app/Version.java | 13 ++++++++----- .../p2p/inventory/GetInventoryRequestHandler.java | 2 +- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/common/src/main/java/bisq/common/app/Version.java b/common/src/main/java/bisq/common/app/Version.java index 729f2003a44..c6345413e01 100644 --- a/common/src/main/java/bisq/common/app/Version.java +++ b/common/src/main/java/bisq/common/app/Version.java @@ -21,6 +21,8 @@ import java.util.Arrays; import java.util.List; +import java.util.Objects; +import java.util.Optional; import java.util.jar.Attributes; import java.util.jar.Manifest; @@ -140,14 +142,15 @@ public static void printVersion() { '}'); } - public String readCommitHash() { + public static Optional findCommitHash() { try { - String pth = getClass().getResource(getClass().getSimpleName() + ".class").toString(); + String pth = Objects.requireNonNull(Version.class.getResource(Version.class.getSimpleName() + ".class")).toString(); String mnf = pth.substring(0, pth.lastIndexOf("!") + 1) + "/META-INF/MANIFEST.MF"; Attributes attr = new Manifest(new URL(mnf).openStream()).getMainAttributes(); - return attr.getValue("Implementation-Version"); - } catch (Exception ignored) { } - return "unknown"; + return Optional.of(attr.getValue("Implementation-Version")); + } catch (Exception ignored) { + return Optional.empty(); + } } public static final byte COMPENSATION_REQUEST = (byte) 0x01; diff --git a/core/src/main/java/bisq/core/network/p2p/inventory/GetInventoryRequestHandler.java b/core/src/main/java/bisq/core/network/p2p/inventory/GetInventoryRequestHandler.java index a8b6f4b7ec3..bbd56528065 100644 --- a/core/src/main/java/bisq/core/network/p2p/inventory/GetInventoryRequestHandler.java +++ b/core/src/main/java/bisq/core/network/p2p/inventory/GetInventoryRequestHandler.java @@ -150,7 +150,7 @@ public void onMessage(NetworkEnvelope networkEnvelope, Connection connection) { // node inventory.put(InventoryItem.version, Version.VERSION); - inventory.put(InventoryItem.commitHash, new Version().readCommitHash()); + Version.findCommitHash().ifPresent(commitHash -> inventory.put(InventoryItem.commitHash, commitHash)); inventory.put(InventoryItem.usedMemory, String.valueOf(Profiler.getUsedMemoryInBytes())); inventory.put(InventoryItem.jvmStartTime, String.valueOf(ManagementFactory.getRuntimeMXBean().getStartTime())); From a1bbac41ea0a9cda74fd31b4730d626893d12c0a Mon Sep 17 00:00:00 2001 From: HenrikJannsen Date: Wed, 7 Dec 2022 11:46:26 -0500 Subject: [PATCH 02/11] Provide commit hash to seed node. Provide full hash without truncating Signed-off-by: HenrikJannsen --- build.gradle | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 04ed710ad26..ce86214697a 100644 --- a/build.gradle +++ b/build.gradle @@ -235,7 +235,7 @@ configure(project(':common')) { ext.getHash = { def p1 = 'git rev-parse HEAD'.execute() p1.waitFor() - return p1.text.substring(0,7) + return p1.text } jar.manifest.attributes( @@ -516,6 +516,10 @@ configure(project(':desktop')) { configure(project(':seednode')) { apply plugin: 'com.github.johnrengelman.shadow' + jar.manifest.attributes( + "Implementation-Title": project.name, + "Implementation-Version": version) + mainClassName = 'bisq.seednode.SeedNodeMain' dependencies { From 37c711a8aad67bda7d068df3c7afad08159bfead Mon Sep 17 00:00:00 2001 From: HenrikJannsen Date: Wed, 7 Dec 2022 11:47:14 -0500 Subject: [PATCH 03/11] Add `distTar.enabled = false` to build Helps to speed up the build. Signed-off-by: HenrikJannsen --- build.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/build.gradle b/build.gradle index ce86214697a..f1d910e9e9e 100644 --- a/build.gradle +++ b/build.gradle @@ -101,6 +101,7 @@ configure([project(':cli'), build.dependsOn installDist installDist.destinationDir = file('build/app') distZip.enabled = false + distTar.enabled = false // the 'installDist' and 'startScripts' blocks below configure bisq executables to put // generated shell scripts in the root project directory, such that users can easily From 96f7db9c80b087e8f751c66a9fb9033264899245 Mon Sep 17 00:00:00 2001 From: HenrikJannsen Date: Wed, 7 Dec 2022 11:47:38 -0500 Subject: [PATCH 04/11] Print log path Signed-off-by: HenrikJannsen --- common/src/main/java/bisq/common/setup/CommonSetup.java | 1 + 1 file changed, 1 insertion(+) diff --git a/common/src/main/java/bisq/common/setup/CommonSetup.java b/common/src/main/java/bisq/common/setup/CommonSetup.java index 0ab19dab310..20d99a22c31 100644 --- a/common/src/main/java/bisq/common/setup/CommonSetup.java +++ b/common/src/main/java/bisq/common/setup/CommonSetup.java @@ -98,6 +98,7 @@ public static void setupUncaughtExceptionHandler(UncaughtExceptionHandler uncaug private static void setupLog(Config config) { String logPath = Paths.get(config.appDataDir.getPath(), "bisq").toString(); Log.setup(logPath); + log.info("Log file at: {}.log", logPath); Utilities.printSysInfo(); Log.setLevel(Level.toLevel(config.logLevel)); } From f4536b6a56ab69f3eef9aa00f94d96fffc259279 Mon Sep 17 00:00:00 2001 From: HenrikJannsen Date: Wed, 7 Dec 2022 11:47:51 -0500 Subject: [PATCH 05/11] Add CompletableFutureUtil Signed-off-by: HenrikJannsen --- .../common/util/CompletableFutureUtil.java | 57 +++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 common/src/main/java/bisq/common/util/CompletableFutureUtil.java diff --git a/common/src/main/java/bisq/common/util/CompletableFutureUtil.java b/common/src/main/java/bisq/common/util/CompletableFutureUtil.java new file mode 100644 index 00000000000..7c885ab4db9 --- /dev/null +++ b/common/src/main/java/bisq/common/util/CompletableFutureUtil.java @@ -0,0 +1,57 @@ +/* + * 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.common.util; + +import java.util.Collection; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +//todo +public class CompletableFutureUtil { + public static CompletableFuture> allOf(Collection> collection) { + //noinspection unchecked + return allOf(collection.toArray(new CompletableFuture[0])); + } + + public static CompletableFuture> allOf(Stream> stream) { + return allOf(stream.collect(Collectors.toList())); + } + + public static CompletableFuture> allOf(CompletableFuture... list) { + CompletableFuture> result = CompletableFuture.allOf(list).thenApply(v -> + Stream.of(list) + .map(future -> { + // We want to return the results in list, not the futures. Once allOf call is complete + // we know that all futures have completed (normally, exceptional or cancelled). + // For exceptional and canceled cases we throw an exception. + T res = future.join(); + if (future.isCompletedExceptionally()) { + throw new RuntimeException((future.handle((r, throwable) -> throwable).join())); + } + if (future.isCancelled()) { + throw new RuntimeException("Future got canceled"); + } + return res; + }) + .collect(Collectors.toList()) + ); + return result; + } +} From 3caf2c2b642da1e9e17579269201cba0e2d49f1b Mon Sep 17 00:00:00 2001 From: HenrikJannsen Date: Wed, 7 Dec 2022 11:50:24 -0500 Subject: [PATCH 06/11] Change visibility (will be used from monitor project). Remove log, change log level. Add getters Signed-off-by: HenrikJannsen --- .../core/provider/ProvidersRepository.java | 2 +- .../core/setup/CoreNetworkCapabilities.java | 2 +- .../bisq/network/p2p/network/Connection.java | 1 - .../bisq/network/p2p/network/Statistic.java | 24 +++++++++++++++++++ .../network/p2p/storage/P2PDataStorage.java | 5 +++- 5 files changed, 30 insertions(+), 4 deletions(-) diff --git a/core/src/main/java/bisq/core/provider/ProvidersRepository.java b/core/src/main/java/bisq/core/provider/ProvidersRepository.java index 9a9d3b23f5f..f176e5a59a1 100644 --- a/core/src/main/java/bisq/core/provider/ProvidersRepository.java +++ b/core/src/main/java/bisq/core/provider/ProvidersRepository.java @@ -35,7 +35,7 @@ @Slf4j public class ProvidersRepository { - private static final List DEFAULT_NODES = Arrays.asList( + public static final List DEFAULT_NODES = Arrays.asList( "http://wizpriceje6q5tdrxkyiazsgu7irquiqjy2dptezqhrtu7l2qelqktid.onion/", // @wiz "http://emzypricpidesmyqg2hc6dkwitqzaxrqnpkdg3ae2wef5znncu2ambqd.onion/", // @emzy "http://aprcndeiwdrkbf4fq7iozxbd27dl72oeo76n7zmjwdi4z34agdrnheyd.onion/", // @mrosseel diff --git a/core/src/main/java/bisq/core/setup/CoreNetworkCapabilities.java b/core/src/main/java/bisq/core/setup/CoreNetworkCapabilities.java index c905f88384d..5f34c365cc9 100644 --- a/core/src/main/java/bisq/core/setup/CoreNetworkCapabilities.java +++ b/core/src/main/java/bisq/core/setup/CoreNetworkCapabilities.java @@ -26,7 +26,7 @@ @Slf4j public class CoreNetworkCapabilities { - static void setSupportedCapabilities(Config config) { + public static void setSupportedCapabilities(Config config) { Capabilities.app.addAll( Capability.TRADE_STATISTICS, Capability.TRADE_STATISTICS_2, diff --git a/p2p/src/main/java/bisq/network/p2p/network/Connection.java b/p2p/src/main/java/bisq/network/p2p/network/Connection.java index a8744d1eba7..3ccf35fc755 100644 --- a/p2p/src/main/java/bisq/network/p2p/network/Connection.java +++ b/p2p/src/main/java/bisq/network/p2p/network/Connection.java @@ -463,7 +463,6 @@ public void shutDown(CloseConnectionReason closeConnectionReason) { } public void shutDown(CloseConnectionReason closeConnectionReason, @Nullable Runnable shutDownCompleteHandler) { - log.info("Connection shutdown started"); log.debug("shutDown: peersNodeAddressOptional={}, closeConnectionReason={}", peersNodeAddressOptional, closeConnectionReason); diff --git a/p2p/src/main/java/bisq/network/p2p/network/Statistic.java b/p2p/src/main/java/bisq/network/p2p/network/Statistic.java index 2f17a0fdb01..234d9fdde4d 100644 --- a/p2p/src/main/java/bisq/network/p2p/network/Statistic.java +++ b/p2p/src/main/java/bisq/network/p2p/network/Statistic.java @@ -238,6 +238,30 @@ public IntegerProperty roundTripTimeProperty() { return roundTripTime; } + public static long getTotalSentBytes() { + return totalSentBytes.get(); + } + + public static double getTotalSentBytesPerSec() { + return totalSentBytesPerSec.get(); + } + + public static long getTotalReceivedBytes() { + return totalReceivedBytes.get(); + } + + public static double getTotalReceivedBytesPerSec() { + return totalReceivedBytesPerSec.get(); + } + + public static double numTotalReceivedMessagesPerSec() { + return numTotalReceivedMessagesPerSec.get(); + } + + public static double getNumTotalSentMessagesPerSec() { + return numTotalSentMessagesPerSec.get(); + } + @Override public String toString() { return "Statistic{" + diff --git a/p2p/src/main/java/bisq/network/p2p/storage/P2PDataStorage.java b/p2p/src/main/java/bisq/network/p2p/storage/P2PDataStorage.java index 38fe02754bb..5b9e46a41d1 100644 --- a/p2p/src/main/java/bisq/network/p2p/storage/P2PDataStorage.java +++ b/p2p/src/main/java/bisq/network/p2p/storage/P2PDataStorage.java @@ -380,7 +380,7 @@ private Map getMapForDataRequest() { serviceMap = service.getMap(); } map.putAll(serviceMap); - log.info("We added {} entries from {} to the excluded key set of our request", + log.debug("We added {} entries from {} to the excluded key set of our request", serviceMap.size(), service.getClass().getSimpleName()); }); return map; @@ -489,6 +489,9 @@ static private Set filterKnownHashes( return new HashSet<>(filteredResults); } + public Collection getPersistableNetworkPayloadCollection() { + return getMapForDataRequest().values(); + } private Set getKeysAsByteSet(Map map) { return map.keySet().stream() From 2c84f07ada913a7c0778c791d9cd684ef546a63f Mon Sep 17 00:00:00 2001 From: HenrikJannsen Date: Wed, 7 Dec 2022 11:51:08 -0500 Subject: [PATCH 07/11] Add value objects and protobuf definitions Signed-off-by: HenrikJannsen --- .../bisq/core/monitor/DoubleValueItem.java | 86 ++++++++++++++ .../bisq/core/monitor/IntegerValueItem.java | 107 ++++++++++++++++++ .../java/bisq/core/monitor/ReportingItem.java | 51 +++++++++ .../bisq/core/monitor/ReportingItems.java | 76 +++++++++++++ .../bisq/core/monitor/StringValueItem.java | 87 ++++++++++++++ proto/src/main/proto/pb.proto | 26 +++++ 6 files changed, 433 insertions(+) create mode 100644 core/src/main/java/bisq/core/monitor/DoubleValueItem.java create mode 100644 core/src/main/java/bisq/core/monitor/IntegerValueItem.java create mode 100644 core/src/main/java/bisq/core/monitor/ReportingItem.java create mode 100644 core/src/main/java/bisq/core/monitor/ReportingItems.java create mode 100644 core/src/main/java/bisq/core/monitor/StringValueItem.java diff --git a/core/src/main/java/bisq/core/monitor/DoubleValueItem.java b/core/src/main/java/bisq/core/monitor/DoubleValueItem.java new file mode 100644 index 00000000000..28f6374e0d7 --- /dev/null +++ b/core/src/main/java/bisq/core/monitor/DoubleValueItem.java @@ -0,0 +1,86 @@ +/* + * 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.monitor; + +import lombok.Getter; +import lombok.Setter; + + +public enum DoubleValueItem implements ReportingItem { + Unspecified("", "Unspecified"), + sentBytesPerSec("network", "sentBytesPerSec"), + receivedBytesPerSec("network", "receivedBytesPerSec"), + receivedMessagesPerSec("network", "receivedMessagesPerSec"), + sentMessagesPerSec("network", "sentMessagesPerSec"); + + + @Getter + @Setter + private String key; + @Getter + @Setter + private String group; + @Getter + @Setter + private double value; + + DoubleValueItem(String group, String key) { + this.group = group; + this.key = key; + } + + public DoubleValueItem withValue(double value) { + setValue(value); + return this; + } + + public static DoubleValueItem from(String key, double value) { + DoubleValueItem item; + try { + item = DoubleValueItem.valueOf(key); + } catch (Throwable t) { + item = DoubleValueItem.Unspecified; + item.setKey(key); + } + + item.setValue(value); + return item; + } + + @Override + public protobuf.ReportingItem toProtoMessage() { + return getBuilder().setDoubleValueItem(protobuf.DoubleValueItem.newBuilder() + .setValue(value)) + .build(); + } + + public static DoubleValueItem fromProto(protobuf.ReportingItem baseProto, protobuf.DoubleValueItem proto) { + return DoubleValueItem.from(baseProto.getKey(), proto.getValue()); + } + + @Override + public String getPath() { + return group + "." + key; + } + + + @Override + public String toString() { + return name() + "= " + value; + } +} diff --git a/core/src/main/java/bisq/core/monitor/IntegerValueItem.java b/core/src/main/java/bisq/core/monitor/IntegerValueItem.java new file mode 100644 index 00000000000..8055eb6335c --- /dev/null +++ b/core/src/main/java/bisq/core/monitor/IntegerValueItem.java @@ -0,0 +1,107 @@ +/* + * 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.monitor; + +import lombok.Getter; +import lombok.Setter; + + +public enum IntegerValueItem implements ReportingItem { + Unspecified("", "Unspecified"), + OfferPayload("data", "OfferPayload"), + MailboxStoragePayload("data", "MailboxStoragePayload"), + TradeStatistics3("data", "TradeStatistics3"), + AccountAgeWitness("data", "AccountAgeWitness"), + SignedWitness("data", "SignedWitness"), + Alert("data", "Alert"), + Filter("data", "Filter"), + Arbitrator("data", "Arbitrator"), + Mediator("data", "Mediator"), + RefundAgent("data", "RefundAgent"), + + TempProposalPayload("dao", "TempProposalPayload"), + ProposalPayload("dao", "ProposalPayload"), + BlindVotePayload("dao", "BlindVotePayload"), + daoStateChainHeight("dao", "daoStateChainHeight"), + blockTimeIsSec("dao", "blockTimeIsSec"), + + maxConnections("network", "maxConnections"), + numConnections("network", "numConnections"), + peakNumConnections("network", "peakNumConnections"), + numAllConnectionsLostEvents("network", "numAllConnectionsLostEvents"), + sentBytes("network", "sentBytes"), + receivedBytes("network", "receivedBytes"), + + usedMemoryInMB("node", "usedMemoryInMB"), + totalMemoryInMB("node", "totalMemoryInMB"), + jvmStartTimeInSec("node", "jvmStartTimeInSec"); + + @Getter + @Setter + private String key; + @Getter + @Setter + private String group; + @Getter + @Setter + private int value; + + IntegerValueItem(String group, String key) { + this.group = group; + this.key = key; + } + + public IntegerValueItem withValue(int value) { + setValue(value); + return this; + } + + public static IntegerValueItem from(String key, int value) { + IntegerValueItem item; + try { + item = IntegerValueItem.valueOf(key); + } catch (Throwable t) { + item = IntegerValueItem.Unspecified; + item.setKey(key); + } + + item.setValue(value); + return item; + } + + @Override + public protobuf.ReportingItem toProtoMessage() { + return getBuilder().setIntegerValueItem(protobuf.IntegerValueItem.newBuilder() + .setValue(value)) + .build(); + } + + public static IntegerValueItem fromProto(protobuf.ReportingItem baseProto, protobuf.IntegerValueItem proto) { + return IntegerValueItem.from(baseProto.getKey(), proto.getValue()); + } + + @Override + public String getPath() { + return group + "." + key; + } + + @Override + public String toString() { + return name() + "= " + value; + } +} diff --git a/core/src/main/java/bisq/core/monitor/ReportingItem.java b/core/src/main/java/bisq/core/monitor/ReportingItem.java new file mode 100644 index 00000000000..887d9761681 --- /dev/null +++ b/core/src/main/java/bisq/core/monitor/ReportingItem.java @@ -0,0 +1,51 @@ +/* + * 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.monitor; + +import bisq.common.proto.ProtobufferRuntimeException; +import bisq.common.proto.network.NetworkPayload; + +public interface ReportingItem extends NetworkPayload { + String getKey(); + + String getGroup(); + + String getPath(); + + default protobuf.ReportingItem.Builder getBuilder() { + return protobuf.ReportingItem.newBuilder() + .setGroup(getGroup()) + .setKey(getKey()); + } + + protobuf.ReportingItem toProtoMessage(); + + static ReportingItem fromProto(protobuf.ReportingItem proto) { + switch (proto.getMessageCase()) { + case STRING_VALUE_ITEM: + return StringValueItem.fromProto(proto, proto.getStringValueItem()); + case INTEGER_VALUE_ITEM: + return IntegerValueItem.fromProto(proto, proto.getIntegerValueItem()); + case DOUBLE_VALUE_ITEM: + return DoubleValueItem.fromProto(proto, proto.getDoubleValueItem()); + case MESSAGE_NOT_SET: + default: + throw new ProtobufferRuntimeException("Unknown message case: " + proto); + } + } +} diff --git a/core/src/main/java/bisq/core/monitor/ReportingItems.java b/core/src/main/java/bisq/core/monitor/ReportingItems.java new file mode 100644 index 00000000000..254fda19449 --- /dev/null +++ b/core/src/main/java/bisq/core/monitor/ReportingItems.java @@ -0,0 +1,76 @@ +/* + * 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.monitor; + +import bisq.common.proto.network.NetworkPayload; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; + +import java.util.ArrayList; +import java.util.stream.Collectors; + +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class ReportingItems extends ArrayList implements NetworkPayload { + @Getter + private final String address; + + public ReportingItems(String address) { + this.address = address; + } + + @Override + public protobuf.ReportingItems toProtoMessage() { + return protobuf.ReportingItems.newBuilder() + .setAddress(address) + .addAllReportingItem(this.stream() + .map(ReportingItem::toProtoMessage) + .collect(Collectors.toList())) + .build(); + } + + public static ReportingItems fromProto(protobuf.ReportingItems proto) { + ReportingItems reportingItems = new ReportingItems(proto.getAddress()); + reportingItems.addAll(proto.getReportingItemList().stream() + .map(ReportingItem::fromProto).collect(Collectors.toList())); + return reportingItems; + } + + public byte[] toProtoMessageAsBytes() { + try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) { + toProtoMessage().writeDelimitedTo(outputStream); + return outputStream.toByteArray(); + } catch (Throwable t) { + log.error("Error at ", t); + throw new RuntimeException(t); + } + } + + public static ReportingItems fromProtoMessageAsBytes(byte[] protoAsBytes) { + try (ByteArrayInputStream inputStream = new ByteArrayInputStream(protoAsBytes)) { + protobuf.ReportingItems proto = protobuf.ReportingItems.parseDelimitedFrom(inputStream); + return fromProto(proto); + } catch (Throwable t) { + log.error("Error at ", t); + throw new RuntimeException(t); + } + } +} diff --git a/core/src/main/java/bisq/core/monitor/StringValueItem.java b/core/src/main/java/bisq/core/monitor/StringValueItem.java new file mode 100644 index 00000000000..0eae92afe9e --- /dev/null +++ b/core/src/main/java/bisq/core/monitor/StringValueItem.java @@ -0,0 +1,87 @@ +/* + * 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.monitor; + +import lombok.Getter; +import lombok.Setter; + + +public enum StringValueItem implements ReportingItem { + Unspecified("", "Unspecified"), + + daoStateHash("dao", "daoStateHash"), + proposalHash("dao", "proposalHash"), + blindVoteHash("dao", "blindVoteHash"), + + version("node", "version"), + commitHash("node", "commitHash"); + + @Getter + @Setter + private String key; + @Getter + @Setter + private String group; + @Getter + @Setter + private String value; + + StringValueItem(String group, String key) { + this.group = group; + this.key = key; + } + + public StringValueItem withValue(String value) { + setValue(value); + return this; + } + + public static StringValueItem from(String key, String value) { + StringValueItem item; + try { + item = StringValueItem.valueOf(key); + } catch (Throwable t) { + item = StringValueItem.Unspecified; + item.setKey(key); + } + + item.setValue(value); + return item; + } + + @Override + public String getPath() { + return group + "." + key; + } + + @Override + public protobuf.ReportingItem toProtoMessage() { + return getBuilder().setStringValueItem(protobuf.StringValueItem.newBuilder() + .setValue(value)) + .build(); + } + + public static StringValueItem fromProto(protobuf.ReportingItem baseProto, protobuf.StringValueItem proto) { + return StringValueItem.from(baseProto.getKey(), proto.getValue()); + } + + @Override + public String toString() { + return name() + "= " + value; + } +} diff --git a/proto/src/main/proto/pb.proto b/proto/src/main/proto/pb.proto index e07e95b506d..ab5c77b3b6d 100644 --- a/proto/src/main/proto/pb.proto +++ b/proto/src/main/proto/pb.proto @@ -2489,3 +2489,29 @@ message MockPayload { string message_version = 1; string message = 2; } + +message ReportingItem { + string key = 1; + string group = 2; + oneof message { + StringValueItem string_value_item = 3; + IntegerValueItem integer_value_item = 4; + DoubleValueItem double_value_item = 5; + } +} +message StringValueItem { + string value = 1; +} + +message IntegerValueItem { + uint32 value = 1; +} + +message DoubleValueItem { + double value = 1; +} + +message ReportingItems { + string address = 1; + repeated ReportingItem reporting_item = 2; +} From 3a4ed1fc01206e9a7b73d15270b9e7780f538a5e Mon Sep 17 00:00:00 2001 From: HenrikJannsen Date: Wed, 7 Dec 2022 11:51:49 -0500 Subject: [PATCH 08/11] Add seedNodeReportingServerUrl option Signed-off-by: HenrikJannsen --- common/src/main/java/bisq/common/config/Config.java | 8 ++++++++ .../main/java/bisq/core/app/misc/ModuleForAppWithP2p.java | 1 + 2 files changed, 9 insertions(+) diff --git a/common/src/main/java/bisq/common/config/Config.java b/common/src/main/java/bisq/common/config/Config.java index 4c2e224887b..985f578428a 100644 --- a/common/src/main/java/bisq/common/config/Config.java +++ b/common/src/main/java/bisq/common/config/Config.java @@ -129,6 +129,7 @@ public class Config { public static final String BYPASS_MEMPOOL_VALIDATION = "bypassMempoolValidation"; public static final String DAO_NODE_API_URL = "daoNodeApiUrl"; public static final String DAO_NODE_API_PORT = "daoNodeApiPort"; + public static final String SEED_NODE_REPORTING_SERVER_URL = "seedNodeReportingServerUrl"; // Default values for certain options public static final int UNSPECIFIED_PORT = -1; @@ -220,6 +221,7 @@ public class Config { public final boolean bypassMempoolValidation; public final String daoNodeApiUrl; public final int daoNodeApiPort; + public final String seedNodeReportingServerUrl; // Properties derived from options but not exposed as options themselves public final File torDir; @@ -679,6 +681,11 @@ public Config(String defaultAppName, File defaultUserDataDir, String... args) { .withRequiredArg() .ofType(Integer.class) .defaultsTo(8082); + ArgumentAcceptingOptionSpec seedNodeReportingServerUrlOpt = + parser.accepts(SEED_NODE_REPORTING_SERVER_URL, "URL of seed node reporting server") + .withRequiredArg() + .ofType(String.class) + .defaultsTo(""); try { CompositeOptionSet options = new CompositeOptionSet(); @@ -799,6 +806,7 @@ public Config(String defaultAppName, File defaultUserDataDir, String... args) { this.bypassMempoolValidation = options.valueOf(bypassMempoolValidationOpt); this.daoNodeApiUrl = options.valueOf(daoNodeApiUrlOpt); this.daoNodeApiPort = options.valueOf(daoNodeApiPortOpt); + this.seedNodeReportingServerUrl = options.valueOf(seedNodeReportingServerUrlOpt); } catch (OptionException ex) { throw new ConfigException("problem parsing option '%s': %s", ex.options().get(0), 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 879c29ab698..f330d61c952 100644 --- a/core/src/main/java/bisq/core/app/misc/ModuleForAppWithP2p.java +++ b/core/src/main/java/bisq/core/app/misc/ModuleForAppWithP2p.java @@ -85,6 +85,7 @@ protected void configure() { bindConstant().annotatedWith(named(USE_DEV_MODE_HEADER)).to(config.useDevModeHeader); bindConstant().annotatedWith(named(REFERRAL_ID)).to(config.referralId); bindConstant().annotatedWith(named(PREVENT_PERIODIC_SHUTDOWN_AT_SEED_NODE)).to(config.preventPeriodicShutdownAtSeedNode); + bindConstant().annotatedWith(named(SEED_NODE_REPORTING_SERVER_URL)).to(config.seedNodeReportingServerUrl); // ordering is used for shut down sequence install(new TradeModule(config)); From f4775f89b0de4570d631efce1a8df1312f5df8b3 Mon Sep 17 00:00:00 2001 From: HenrikJannsen Date: Wed, 7 Dec 2022 13:23:28 -0500 Subject: [PATCH 09/11] Add SeedNodeReportingService Signed-off-by: HenrikJannsen --- .../bisq/core/monitor/DoubleValueItem.java | 2 +- .../bisq/core/monitor/IntegerValueItem.java | 2 +- .../bisq/core/monitor/StringValueItem.java | 2 +- .../src/main/java/bisq/seednode/SeedNode.java | 17 +- .../seednode/SeedNodeReportingService.java | 281 ++++++++++++++++++ 5 files changed, 300 insertions(+), 4 deletions(-) create mode 100644 seednode/src/main/java/bisq/seednode/SeedNodeReportingService.java diff --git a/core/src/main/java/bisq/core/monitor/DoubleValueItem.java b/core/src/main/java/bisq/core/monitor/DoubleValueItem.java index 28f6374e0d7..15530d7cb38 100644 --- a/core/src/main/java/bisq/core/monitor/DoubleValueItem.java +++ b/core/src/main/java/bisq/core/monitor/DoubleValueItem.java @@ -81,6 +81,6 @@ public String getPath() { @Override public String toString() { - return name() + "= " + value; + return name() + "=" + value; } } diff --git a/core/src/main/java/bisq/core/monitor/IntegerValueItem.java b/core/src/main/java/bisq/core/monitor/IntegerValueItem.java index 8055eb6335c..06253f1ee67 100644 --- a/core/src/main/java/bisq/core/monitor/IntegerValueItem.java +++ b/core/src/main/java/bisq/core/monitor/IntegerValueItem.java @@ -102,6 +102,6 @@ public String getPath() { @Override public String toString() { - return name() + "= " + value; + return name() + "=" + value; } } diff --git a/core/src/main/java/bisq/core/monitor/StringValueItem.java b/core/src/main/java/bisq/core/monitor/StringValueItem.java index 0eae92afe9e..f698b30bae0 100644 --- a/core/src/main/java/bisq/core/monitor/StringValueItem.java +++ b/core/src/main/java/bisq/core/monitor/StringValueItem.java @@ -82,6 +82,6 @@ public static StringValueItem fromProto(protobuf.ReportingItem baseProto, protob @Override public String toString() { - return name() + "= " + value; + return name() + "=" + value; } } diff --git a/seednode/src/main/java/bisq/seednode/SeedNode.java b/seednode/src/main/java/bisq/seednode/SeedNode.java index ff2f2609d3d..996acedb9b0 100644 --- a/seednode/src/main/java/bisq/seednode/SeedNode.java +++ b/seednode/src/main/java/bisq/seednode/SeedNode.java @@ -21,7 +21,11 @@ import bisq.core.app.misc.AppSetupWithP2PAndDAO; import bisq.core.network.p2p.inventory.GetInventoryRequestHandler; +import bisq.common.config.Config; + import com.google.inject.Injector; +import com.google.inject.Key; +import com.google.inject.name.Names; import lombok.Setter; import lombok.extern.slf4j.Slf4j; @@ -32,6 +36,7 @@ public class SeedNode { private Injector injector; private AppSetup appSetup; private GetInventoryRequestHandler getInventoryRequestHandler; + private SeedNodeReportingService seedNodeReportingService; public SeedNode() { } @@ -41,9 +46,19 @@ public void startApplication() { appSetup.start(); getInventoryRequestHandler = injector.getInstance(GetInventoryRequestHandler.class); + + String seedNodeReportingServerUrl = injector.getInstance(Key.get(String.class, Names.named(Config.SEED_NODE_REPORTING_SERVER_URL))); + if (seedNodeReportingServerUrl != null && !seedNodeReportingServerUrl.trim().isEmpty()) { + seedNodeReportingService = injector.getInstance(SeedNodeReportingService.class); + } } public void shutDown() { - getInventoryRequestHandler.shutDown(); + if (getInventoryRequestHandler != null) { + getInventoryRequestHandler.shutDown(); + } + if (seedNodeReportingService != null) { + seedNodeReportingService.shutDown(); + } } } diff --git a/seednode/src/main/java/bisq/seednode/SeedNodeReportingService.java b/seednode/src/main/java/bisq/seednode/SeedNodeReportingService.java new file mode 100644 index 00000000000..25c91007c83 --- /dev/null +++ b/seednode/src/main/java/bisq/seednode/SeedNodeReportingService.java @@ -0,0 +1,281 @@ +/* + * 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.seednode; + +import bisq.core.dao.DaoFacade; +import bisq.core.dao.monitoring.BlindVoteStateMonitoringService; +import bisq.core.dao.monitoring.DaoStateMonitoringService; +import bisq.core.dao.monitoring.ProposalStateMonitoringService; +import bisq.core.dao.monitoring.model.BlindVoteStateBlock; +import bisq.core.dao.monitoring.model.DaoStateBlock; +import bisq.core.dao.monitoring.model.ProposalStateBlock; +import bisq.core.dao.state.DaoStateListener; +import bisq.core.dao.state.DaoStateService; +import bisq.core.monitor.DoubleValueItem; +import bisq.core.monitor.IntegerValueItem; +import bisq.core.monitor.ReportingItems; +import bisq.core.monitor.StringValueItem; + +import bisq.network.p2p.P2PService; +import bisq.network.p2p.network.NetworkNode; +import bisq.network.p2p.network.Statistic; +import bisq.network.p2p.peers.PeerManager; +import bisq.network.p2p.storage.P2PDataStorage; +import bisq.network.p2p.storage.payload.ProtectedStorageEntry; + +import bisq.common.Timer; +import bisq.common.UserThread; +import bisq.common.app.Version; +import bisq.common.config.Config; +import bisq.common.util.Profiler; +import bisq.common.util.Utilities; + +import javax.inject.Inject; +import javax.inject.Named; +import javax.inject.Singleton; + +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; + +import java.io.IOException; + +import java.util.HashMap; +import java.util.LinkedList; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; +import java.util.stream.Stream; + +import java.lang.management.ManagementFactory; + +import lombok.extern.slf4j.Slf4j; + +/** + * Sends reporting data to monitoring server via clear net. + * The seed node is configured with nginx as proxy which takes care of TLS handling and provides the client key. + * + * We send on a regular interval every 60 seconds the used memory metric data which serves as a heartbeat to signal the + * monitor that the seed node is alive. + * We send every 5 minutes the network data, network load data and node specific data. + * At each new block we send the DAO hashes and block height. + */ +@Slf4j +@Singleton +public class SeedNodeReportingService { + private final static long REPORT_DELAY_SEC = TimeUnit.MINUTES.toSeconds(5); + private final static long HEART_BEAT_DELAY_SEC = TimeUnit.MINUTES.toSeconds(1); + + private final P2PService p2PService; + private final NetworkNode networkNode; + private final PeerManager peerManager; + private final P2PDataStorage p2PDataStorage; + private final DaoStateService daoStateService; + private final DaoStateMonitoringService daoStateMonitoringService; + private final ProposalStateMonitoringService proposalStateMonitoringService; + private final BlindVoteStateMonitoringService blindVoteStateMonitoringService; + private final int maxConnections; + private final String seedNodeReportingServerUrl; + private final DaoStateListener daoStateListener; + private final HttpClient httpClient; + + private Timer dataReportTimer; + private final Timer heartBeatTimer; + private final ThreadPoolExecutor executor; + + @Inject + public SeedNodeReportingService(P2PService p2PService, + DaoFacade daoFacade, + NetworkNode networkNode, + PeerManager peerManager, + P2PDataStorage p2PDataStorage, + DaoStateService daoStateService, + DaoStateMonitoringService daoStateMonitoringService, + ProposalStateMonitoringService proposalStateMonitoringService, + BlindVoteStateMonitoringService blindVoteStateMonitoringService, + @Named(Config.MAX_CONNECTIONS) int maxConnections, + @Named(Config.SEED_NODE_REPORTING_SERVER_URL) String seedNodeReportingServerUrl) { + this.p2PService = p2PService; + this.networkNode = networkNode; + this.peerManager = peerManager; + this.p2PDataStorage = p2PDataStorage; + this.daoStateService = daoStateService; + this.daoStateMonitoringService = daoStateMonitoringService; + this.proposalStateMonitoringService = proposalStateMonitoringService; + this.blindVoteStateMonitoringService = blindVoteStateMonitoringService; + this.maxConnections = maxConnections; + this.seedNodeReportingServerUrl = seedNodeReportingServerUrl; + + executor = Utilities.getThreadPoolExecutor("SeedNodeReportingService", 2, 4, 30); + httpClient = HttpClient.newHttpClient(); + + heartBeatTimer = UserThread.runPeriodically(this::sendHeartBeat, HEART_BEAT_DELAY_SEC); + + // We send each time when a new block is received and the DAO hash has been provided (which + // takes a bit after the block arrives). + daoStateMonitoringService.addListener(new DaoStateMonitoringService.Listener() { + @Override + public void onDaoStateHashesChanged() { + sendBlockRelatedData(); + } + + @Override + public void onCheckpointFail() { + } + }); + + // Independent of the block + daoStateListener = new DaoStateListener() { + @Override + public void onParseBlockChainComplete() { + daoFacade.removeBsqStateListener(daoStateListener); + dataReportTimer = UserThread.runPeriodically(() -> sendDataReport(), REPORT_DELAY_SEC); + sendDataReport(); + + sendBlockRelatedData(); + } + }; + daoFacade.addBsqStateListener(daoStateListener); + } + + public void shutDown() { + if (heartBeatTimer != null) { + heartBeatTimer.stop(); + } + if (dataReportTimer != null) { + dataReportTimer.stop(); + } + + Utilities.shutdownAndAwaitTermination(executor, 2, TimeUnit.SECONDS); + } + + private void sendHeartBeat() { + if (p2PService.getAddress() == null) { + return; + } + ReportingItems reportingItems = new ReportingItems(getMyAddress()); + reportingItems.add(IntegerValueItem.usedMemoryInMB.withValue((int) Profiler.getUsedMemoryInMB())); + sendReportingItems(reportingItems); + } + + private void sendBlockRelatedData() { + if (p2PService.getAddress() == null) { + return; + } + + ReportingItems reportingItems = new ReportingItems(getMyAddress()); + int daoStateChainHeight = daoStateService.getChainHeight(); + reportingItems.add(IntegerValueItem.daoStateChainHeight.withValue(daoStateChainHeight)); + daoStateService.getLastBlock().map(block -> (int) (block.getTime() / 1000)) + .ifPresent(blockTime -> reportingItems.add(IntegerValueItem.blockTimeIsSec.withValue(blockTime))); + LinkedList daoStateBlockChain = daoStateMonitoringService.getDaoStateBlockChain(); + if (!daoStateBlockChain.isEmpty()) { + String daoStateHash = Utilities.bytesAsHexString(daoStateBlockChain.getLast().getMyStateHash().getHash()); + reportingItems.add(StringValueItem.daoStateHash.withValue(daoStateHash)); + } + + LinkedList proposalStateBlockChain = proposalStateMonitoringService.getProposalStateBlockChain(); + if (!proposalStateBlockChain.isEmpty()) { + String proposalHash = Utilities.bytesAsHexString(proposalStateBlockChain.getLast().getMyStateHash().getHash()); + reportingItems.add(StringValueItem.proposalHash.withValue(proposalHash)); + } + + LinkedList blindVoteStateBlockChain = blindVoteStateMonitoringService.getBlindVoteStateBlockChain(); + if (!blindVoteStateBlockChain.isEmpty()) { + String blindVoteHash = Utilities.bytesAsHexString(blindVoteStateBlockChain.getLast().getMyStateHash().getHash()); + reportingItems.add(StringValueItem.blindVoteHash.withValue(blindVoteHash)); + } + + sendReportingItems(reportingItems); + } + + private void sendDataReport() { + if (p2PService.getAddress() == null) { + return; + } + + ReportingItems reportingItems = new ReportingItems(getMyAddress()); + + // Data + Map numItemsByType = new HashMap<>(); + Stream.concat(p2PDataStorage.getPersistableNetworkPayloadCollection().stream() + .map(payload -> payload.getClass().getSimpleName()), + p2PDataStorage.getMap().values().stream() + .map(ProtectedStorageEntry::getProtectedStoragePayload) + .map(payload -> payload.getClass().getSimpleName())) + .forEach(className -> { + numItemsByType.putIfAbsent(className, 0); + numItemsByType.put(className, numItemsByType.get(className) + 1); + }); + numItemsByType.forEach((key, value) -> reportingItems.add(IntegerValueItem.from(key, value))); + + // Network + reportingItems.add(IntegerValueItem.numConnections.withValue(networkNode.getAllConnections().size())); + reportingItems.add(IntegerValueItem.peakNumConnections.withValue(peerManager.getPeakNumConnections())); + reportingItems.add(IntegerValueItem.numAllConnectionsLostEvents.withValue(peerManager.getNumAllConnectionsLostEvents())); + reportingItems.add(IntegerValueItem.sentBytes.withValue((int) Statistic.getTotalSentBytes())); + reportingItems.add(IntegerValueItem.receivedBytes.withValue((int) Statistic.getTotalReceivedBytes())); + reportingItems.add(DoubleValueItem.sentBytesPerSec.withValue(Statistic.getTotalSentBytesPerSec())); + reportingItems.add(DoubleValueItem.sentMessagesPerSec.withValue(Statistic.getNumTotalSentMessagesPerSec())); + reportingItems.add(DoubleValueItem.receivedBytesPerSec.withValue(Statistic.getTotalReceivedBytesPerSec())); + reportingItems.add(DoubleValueItem.receivedMessagesPerSec.withValue(Statistic.numTotalReceivedMessagesPerSec())); + + // Node + reportingItems.add(IntegerValueItem.usedMemoryInMB.withValue((int) Profiler.getUsedMemoryInMB())); + reportingItems.add(IntegerValueItem.totalMemoryInMB.withValue((int) Profiler.getTotalMemoryInMB())); + reportingItems.add(IntegerValueItem.jvmStartTimeInSec.withValue((int) (ManagementFactory.getRuntimeMXBean().getStartTime() / 1000))); + reportingItems.add(IntegerValueItem.maxConnections.withValue(maxConnections)); + reportingItems.add(StringValueItem.version.withValue(Version.VERSION)); + + // If no commit hash is found we use 0 in hex format + String commitHash = Version.findCommitHash().orElse("00"); + reportingItems.add(StringValueItem.commitHash.withValue(commitHash)); + + sendReportingItems(reportingItems); + } + + private void sendReportingItems(ReportingItems reportingItems) { + CompletableFuture.runAsync(() -> { + log.info("Send report to monitor server: {}", reportingItems.toString()); + // We send the data as hex encoded protobuf data. We do not use the envelope as it is not part of the p2p system. + byte[] protoMessageAsBytes = reportingItems.toProtoMessageAsBytes(); + try { + HttpRequest request = HttpRequest.newBuilder() + .uri(URI.create(seedNodeReportingServerUrl)) + .POST(HttpRequest.BodyPublishers.ofByteArray(protoMessageAsBytes)) + .header("User-Agent", getMyAddress()) + .build(); + HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); + if (response.statusCode() != 200) { + log.error("Response error message: {}", response); + } + } catch (IOException e) { + log.warn("IOException at sending reporting. {}", e.getMessage()); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + }, executor); + } + + private String getMyAddress() { + return p2PService.getAddress() != null ? p2PService.getAddress().getFullAddress() : "N/A"; + } + +} From 3308e35e8c23e0ed015ba72c7ebb5b3304918202 Mon Sep 17 00:00:00 2001 From: HenrikJannsen Date: Thu, 8 Dec 2022 09:56:11 -0500 Subject: [PATCH 10/11] Add newCachedThreadPool to Utilities Use newCachedThreadPool instead of getThreadPoolExecutor Utilities.getThreadPoolExecutor use a BlockingQueue which prevents the intended behaviour to increase the pool size to the max value. Signed-off-by: HenrikJannsen --- common/src/main/java/bisq/common/util/Utilities.java | 7 +++++++ .../main/java/bisq/seednode/SeedNodeReportingService.java | 6 +++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/common/src/main/java/bisq/common/util/Utilities.java b/common/src/main/java/bisq/common/util/Utilities.java index fca323ab4c8..ae97e2c2bef 100644 --- a/common/src/main/java/bisq/common/util/Utilities.java +++ b/common/src/main/java/bisq/common/util/Utilities.java @@ -64,6 +64,7 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledThreadPoolExecutor; +import java.util.concurrent.SynchronousQueue; import java.util.concurrent.ThreadFactory; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; @@ -135,6 +136,12 @@ private static ThreadPoolExecutor getThreadPoolExecutor(String name, return executor; } + public static ExecutorService newCachedThreadPool(int maximumPoolSize) { + return new ThreadPoolExecutor(0, maximumPoolSize, + 60, TimeUnit.SECONDS, + new SynchronousQueue<>()); + } + @SuppressWarnings("SameParameterValue") public static ScheduledThreadPoolExecutor getScheduledThreadPoolExecutor(String name, int corePoolSize, diff --git a/seednode/src/main/java/bisq/seednode/SeedNodeReportingService.java b/seednode/src/main/java/bisq/seednode/SeedNodeReportingService.java index 25c91007c83..2df102a5019 100644 --- a/seednode/src/main/java/bisq/seednode/SeedNodeReportingService.java +++ b/seednode/src/main/java/bisq/seednode/SeedNodeReportingService.java @@ -60,7 +60,7 @@ import java.util.LinkedList; import java.util.Map; import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.ExecutorService; import java.util.concurrent.TimeUnit; import java.util.stream.Stream; @@ -98,7 +98,7 @@ public class SeedNodeReportingService { private Timer dataReportTimer; private final Timer heartBeatTimer; - private final ThreadPoolExecutor executor; + private final ExecutorService executor; @Inject public SeedNodeReportingService(P2PService p2PService, @@ -123,7 +123,7 @@ public SeedNodeReportingService(P2PService p2PService, this.maxConnections = maxConnections; this.seedNodeReportingServerUrl = seedNodeReportingServerUrl; - executor = Utilities.getThreadPoolExecutor("SeedNodeReportingService", 2, 4, 30); + executor = Utilities.newCachedThreadPool(5); httpClient = HttpClient.newHttpClient(); heartBeatTimer = UserThread.runPeriodically(this::sendHeartBeat, HEART_BEAT_DELAY_SEC); From f98cd04fd8706b1f4b9c6b06658c9f802a566660 Mon Sep 17 00:00:00 2001 From: HenrikJannsen Date: Fri, 9 Dec 2022 08:54:28 -0500 Subject: [PATCH 11/11] Use LongValueItem instead of IntegerValueItem Signed-off-by: HenrikJannsen --- ...tegerValueItem.java => LongValueItem.java} | 22 +++++++------- .../java/bisq/core/monitor/ReportingItem.java | 4 +-- proto/src/main/proto/pb.proto | 6 ++-- .../seednode/SeedNodeReportingService.java | 30 +++++++++---------- 4 files changed, 31 insertions(+), 31 deletions(-) rename core/src/main/java/bisq/core/monitor/{IntegerValueItem.java => LongValueItem.java} (80%) diff --git a/core/src/main/java/bisq/core/monitor/IntegerValueItem.java b/core/src/main/java/bisq/core/monitor/LongValueItem.java similarity index 80% rename from core/src/main/java/bisq/core/monitor/IntegerValueItem.java rename to core/src/main/java/bisq/core/monitor/LongValueItem.java index 06253f1ee67..590e852ab8f 100644 --- a/core/src/main/java/bisq/core/monitor/IntegerValueItem.java +++ b/core/src/main/java/bisq/core/monitor/LongValueItem.java @@ -21,7 +21,7 @@ import lombok.Setter; -public enum IntegerValueItem implements ReportingItem { +public enum LongValueItem implements ReportingItem { Unspecified("", "Unspecified"), OfferPayload("data", "OfferPayload"), MailboxStoragePayload("data", "MailboxStoragePayload"), @@ -59,24 +59,24 @@ public enum IntegerValueItem implements ReportingItem { private String group; @Getter @Setter - private int value; + private long value; - IntegerValueItem(String group, String key) { + LongValueItem(String group, String key) { this.group = group; this.key = key; } - public IntegerValueItem withValue(int value) { + public LongValueItem withValue(long value) { setValue(value); return this; } - public static IntegerValueItem from(String key, int value) { - IntegerValueItem item; + public static LongValueItem from(String key, long value) { + LongValueItem item; try { - item = IntegerValueItem.valueOf(key); + item = LongValueItem.valueOf(key); } catch (Throwable t) { - item = IntegerValueItem.Unspecified; + item = LongValueItem.Unspecified; item.setKey(key); } @@ -86,13 +86,13 @@ public static IntegerValueItem from(String key, int value) { @Override public protobuf.ReportingItem toProtoMessage() { - return getBuilder().setIntegerValueItem(protobuf.IntegerValueItem.newBuilder() + return getBuilder().setLongValueItem(protobuf.LongValueItem.newBuilder() .setValue(value)) .build(); } - public static IntegerValueItem fromProto(protobuf.ReportingItem baseProto, protobuf.IntegerValueItem proto) { - return IntegerValueItem.from(baseProto.getKey(), proto.getValue()); + public static LongValueItem fromProto(protobuf.ReportingItem baseProto, protobuf.LongValueItem proto) { + return LongValueItem.from(baseProto.getKey(), proto.getValue()); } @Override diff --git a/core/src/main/java/bisq/core/monitor/ReportingItem.java b/core/src/main/java/bisq/core/monitor/ReportingItem.java index 887d9761681..54ad91f040f 100644 --- a/core/src/main/java/bisq/core/monitor/ReportingItem.java +++ b/core/src/main/java/bisq/core/monitor/ReportingItem.java @@ -39,8 +39,8 @@ static ReportingItem fromProto(protobuf.ReportingItem proto) { switch (proto.getMessageCase()) { case STRING_VALUE_ITEM: return StringValueItem.fromProto(proto, proto.getStringValueItem()); - case INTEGER_VALUE_ITEM: - return IntegerValueItem.fromProto(proto, proto.getIntegerValueItem()); + case LONG_VALUE_ITEM: + return LongValueItem.fromProto(proto, proto.getLongValueItem()); case DOUBLE_VALUE_ITEM: return DoubleValueItem.fromProto(proto, proto.getDoubleValueItem()); case MESSAGE_NOT_SET: diff --git a/proto/src/main/proto/pb.proto b/proto/src/main/proto/pb.proto index ab5c77b3b6d..6d229e5b126 100644 --- a/proto/src/main/proto/pb.proto +++ b/proto/src/main/proto/pb.proto @@ -2495,7 +2495,7 @@ message ReportingItem { string group = 2; oneof message { StringValueItem string_value_item = 3; - IntegerValueItem integer_value_item = 4; + LongValueItem long_value_item = 4; DoubleValueItem double_value_item = 5; } } @@ -2503,8 +2503,8 @@ message StringValueItem { string value = 1; } -message IntegerValueItem { - uint32 value = 1; +message LongValueItem { + uint64 value = 1; } message DoubleValueItem { diff --git a/seednode/src/main/java/bisq/seednode/SeedNodeReportingService.java b/seednode/src/main/java/bisq/seednode/SeedNodeReportingService.java index 2df102a5019..f8feb943410 100644 --- a/seednode/src/main/java/bisq/seednode/SeedNodeReportingService.java +++ b/seednode/src/main/java/bisq/seednode/SeedNodeReportingService.java @@ -27,7 +27,7 @@ import bisq.core.dao.state.DaoStateListener; import bisq.core.dao.state.DaoStateService; import bisq.core.monitor.DoubleValueItem; -import bisq.core.monitor.IntegerValueItem; +import bisq.core.monitor.LongValueItem; import bisq.core.monitor.ReportingItems; import bisq.core.monitor.StringValueItem; @@ -171,7 +171,7 @@ private void sendHeartBeat() { return; } ReportingItems reportingItems = new ReportingItems(getMyAddress()); - reportingItems.add(IntegerValueItem.usedMemoryInMB.withValue((int) Profiler.getUsedMemoryInMB())); + reportingItems.add(LongValueItem.usedMemoryInMB.withValue(Profiler.getUsedMemoryInMB())); sendReportingItems(reportingItems); } @@ -182,9 +182,9 @@ private void sendBlockRelatedData() { ReportingItems reportingItems = new ReportingItems(getMyAddress()); int daoStateChainHeight = daoStateService.getChainHeight(); - reportingItems.add(IntegerValueItem.daoStateChainHeight.withValue(daoStateChainHeight)); - daoStateService.getLastBlock().map(block -> (int) (block.getTime() / 1000)) - .ifPresent(blockTime -> reportingItems.add(IntegerValueItem.blockTimeIsSec.withValue(blockTime))); + reportingItems.add(LongValueItem.daoStateChainHeight.withValue(daoStateChainHeight)); + daoStateService.getLastBlock().map(block -> (block.getTime() / 1000)) + .ifPresent(blockTime -> reportingItems.add(LongValueItem.blockTimeIsSec.withValue(blockTime))); LinkedList daoStateBlockChain = daoStateMonitoringService.getDaoStateBlockChain(); if (!daoStateBlockChain.isEmpty()) { String daoStateHash = Utilities.bytesAsHexString(daoStateBlockChain.getLast().getMyStateHash().getHash()); @@ -224,24 +224,24 @@ private void sendDataReport() { numItemsByType.putIfAbsent(className, 0); numItemsByType.put(className, numItemsByType.get(className) + 1); }); - numItemsByType.forEach((key, value) -> reportingItems.add(IntegerValueItem.from(key, value))); + numItemsByType.forEach((key, value) -> reportingItems.add(LongValueItem.from(key, value))); // Network - reportingItems.add(IntegerValueItem.numConnections.withValue(networkNode.getAllConnections().size())); - reportingItems.add(IntegerValueItem.peakNumConnections.withValue(peerManager.getPeakNumConnections())); - reportingItems.add(IntegerValueItem.numAllConnectionsLostEvents.withValue(peerManager.getNumAllConnectionsLostEvents())); - reportingItems.add(IntegerValueItem.sentBytes.withValue((int) Statistic.getTotalSentBytes())); - reportingItems.add(IntegerValueItem.receivedBytes.withValue((int) Statistic.getTotalReceivedBytes())); + reportingItems.add(LongValueItem.numConnections.withValue(networkNode.getAllConnections().size())); + reportingItems.add(LongValueItem.peakNumConnections.withValue(peerManager.getPeakNumConnections())); + reportingItems.add(LongValueItem.numAllConnectionsLostEvents.withValue(peerManager.getNumAllConnectionsLostEvents())); + reportingItems.add(LongValueItem.sentBytes.withValue(Statistic.getTotalSentBytes())); + reportingItems.add(LongValueItem.receivedBytes.withValue(Statistic.getTotalReceivedBytes())); reportingItems.add(DoubleValueItem.sentBytesPerSec.withValue(Statistic.getTotalSentBytesPerSec())); reportingItems.add(DoubleValueItem.sentMessagesPerSec.withValue(Statistic.getNumTotalSentMessagesPerSec())); reportingItems.add(DoubleValueItem.receivedBytesPerSec.withValue(Statistic.getTotalReceivedBytesPerSec())); reportingItems.add(DoubleValueItem.receivedMessagesPerSec.withValue(Statistic.numTotalReceivedMessagesPerSec())); // Node - reportingItems.add(IntegerValueItem.usedMemoryInMB.withValue((int) Profiler.getUsedMemoryInMB())); - reportingItems.add(IntegerValueItem.totalMemoryInMB.withValue((int) Profiler.getTotalMemoryInMB())); - reportingItems.add(IntegerValueItem.jvmStartTimeInSec.withValue((int) (ManagementFactory.getRuntimeMXBean().getStartTime() / 1000))); - reportingItems.add(IntegerValueItem.maxConnections.withValue(maxConnections)); + reportingItems.add(LongValueItem.usedMemoryInMB.withValue(Profiler.getUsedMemoryInMB())); + reportingItems.add(LongValueItem.totalMemoryInMB.withValue(Profiler.getTotalMemoryInMB())); + reportingItems.add(LongValueItem.jvmStartTimeInSec.withValue((ManagementFactory.getRuntimeMXBean().getStartTime() / 1000))); + reportingItems.add(LongValueItem.maxConnections.withValue(maxConnections)); reportingItems.add(StringValueItem.version.withValue(Version.VERSION)); // If no commit hash is found we use 0 in hex format