diff --git a/.gitignore b/.gitignore index b1cc84ff079..25ccd9afd15 100644 --- a/.gitignore +++ b/.gitignore @@ -30,8 +30,6 @@ desktop.ini *.class deploy */releases/* -/monitor/TorHiddenServiceStartupTimeTests/* -/monitor/monitor-tor/* .java-version .localnet /apitest/src/main/resources/dao-setup* diff --git a/Makefile b/Makefile index 58ff18290b2..1575383b664 100644 --- a/Makefile +++ b/Makefile @@ -37,7 +37,6 @@ # # $ ls -1 bisq-* # bisq-desktop -# bisq-monitor # bisq-relay # bisq-seednode # bisq-statsnode diff --git a/build.gradle b/build.gradle index aebb42af476..5c4ae044e06 100644 --- a/build.gradle +++ b/build.gradle @@ -93,7 +93,6 @@ configure(subprojects) { configure([project(':cli'), project(':daemon'), project(':desktop'), - project(':monitor'), project(':seednode'), project(':statsnode'), project(':apitest')]) { @@ -506,52 +505,6 @@ configure(project(':desktop')) { } -configure(project(':monitor')) { - apply plugin: 'org.openjfx.javafxplugin' - - javafx { - version = "$javafxVersion" - modules = ['javafx.base'] - } - - mainClassName = 'bisq.monitor.Monitor' - - test { - useJUnitPlatform() - testLogging { - events "passed", "skipped", "failed" - } - } - - dependencies { - implementation project(':assets') - implementation project(':common') - implementation project(':core') - implementation project(':p2p') - annotationProcessor "org.projectlombok:lombok:$lombokVersion" - compileOnly "org.projectlombok:lombok:$lombokVersion" - implementation "ch.qos.logback:logback-classic:$logbackVersion" - implementation "ch.qos.logback:logback-core:$logbackVersion" - implementation "com.google.guava:guava:$guavaVersion" - implementation "org.slf4j:slf4j-api:$slf4jVersion" - implementation("com.github.bisq-network.netlayer:tor.external:$netlayerVersion") { - exclude(module: 'slf4j-api') - } - implementation("com.github.bisq-network.netlayer:tor.native:$netlayerVersion") { - exclude(module: 'slf4j-api') - } - implementation("com.google.inject:guice:$guiceVersion") { - exclude(module: 'guava') - } - testAnnotationProcessor "org.projectlombok:lombok:$lombokVersion" - testCompileOnly "org.projectlombok:lombok:$lombokVersion" - testImplementation "org.junit.jupiter:junit-jupiter-api:$jupiterVersion" - testImplementation "org.junit.jupiter:junit-jupiter-params:$jupiterVersion" - testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:$jupiterVersion") - } -} - - configure(project(':seednode')) { apply plugin: 'com.github.johnrengelman.shadow' diff --git a/monitor/README.md b/monitor/README.md deleted file mode 100644 index f2ed142b89a..00000000000 --- a/monitor/README.md +++ /dev/null @@ -1,246 +0,0 @@ -# Bisq Network Monitor Node - -The Bisq monitor node collects a set of metrics which are of interest to developers and users alike. These metrics are then made available through reporters. - -The *Settled* release features these metrics: -- Tor Startup Time: The time it takes to start Tor starting at a clean system, unpacking the shipped Tor binaries, firing up Tor until Tor is connected to the Tor network and ready to use. -- Tor Roundtrip Time: Given a bootstrapped Tor, the roundtrip time of connecting to a hidden service is measured. -- Tor Hidden Service Startup Time: Given a bootstrapped Tor, the time it takes to create and announce a freshly created hidden service. -- P2P Round Trip Time: A metric hitchhiking the Ping/Pong messages of the Keep-Alive-Mechanism to determine the Round Trip Time when issuing a Ping to a seed node. -- P2P Seed Node Message Snapshot: Get absolute number and constellation of messages a fresh Bisq client will get on startup. Also reports diffs between seed nodes on a per-message-type basis. -- P2P Network Load: listens to the P2P network and its broadcast messages. Reports every X seconds. -- P2P Market Statistics: a demonstration metric which extracts market information from broadcast messages. This demo implementation reports the number of open offers per market. - - -The *Settled* release features these reporters: -- A reporter that simply writes the findings to `System.err` -- A reporter that reports the findings to a Graphite/Carbon instance using the [plaintext protocol](https://graphite.readthedocs.io/en/latest/feeding-carbon.html#the-plaintext-protocol) - -## Configuration - -The *Bisq Network Monitor Node* is to be configured via a Java properties file. There is a default configuration file shipped with the monitor which reports to the one monitoring service currently up and running. - -If you want to tweak the configuration, you can pass the location of the file as command line parameter: - -``` -./bisq-monitor /path/to/your/config.properties -``` - -A sample configuration file looks like follows: - -``` -## System configuration - -# true overwrites the reporters picked by the developers (for debugging for example) (defaults to false) -System.useConsoleReporter=true - -# 0 -> BTC_MAINNET, 1 -> BTC_TESTNET (default) -System.baseCurrencyNetwork=0 - -## Each Metric is configured via a set of properties. -## -## The minimal set of properties required to run a Metric is: -## -## YourMetricName.enabled=true|false -## YourMetricName.run.interval=10 [seconds] - -#Edit and uncomment the lines below to your liking - -#TorStartupTime Metric -TorStartupTime.enabled=true -TorStartupTime.run.interval=100 -TorStartupTime.run.socksPort=90500 # so that there is no interference with a system Tor - -#TorRoundTripTime Metric -TorRoundTripTime.enabled=true -TorRoundTripTime.run.interval=100 -TorRoundTripTime.run.sampleSize=5 -TorRoundTripTime.run.hosts=http://expyuzz4wqqyqhjn.onion:80 # torproject.org hidden service - -#TorHiddenServiceStartupTime Metric -TorHiddenServiceStartupTime.enabled=true -TorHiddenServiceStartupTime.run.interval=100 -TorHiddenServiceStartupTime.run.localPort=90501 # so that there is no interference with a system Tor -TorHiddenServiceStartupTime.run.servicePort=90511 # so that there is no interference with a system Tor - -#P2PRoundTripTime Metric -P2PRoundTripTime.enabled=true -P2PRoundTripTime.run.interval=100 -P2PRoundTripTime.run.sampleSize=5 -P2PRoundTripTime.run.hosts=723ljisnynbtdohi.onion:8000, fl3mmribyxgrv63c.onion:8000 -P2PRoundTripTime.run.torProxyPort=9060 - -#P2PNetworkLoad Metric -P2PNetworkLoad.enabled=true -P2PNetworkLoad.run.interval=100 -P2PNetworkLoad.run.torProxyPort=9061 -P2PNetworkLoad.run.historySize=500 - -#P2PNetworkMessageSnapshot Metric -P2PSeedNodeSnapshot.enabled=true -P2PSeedNodeSnapshot.run.interval=24 -P2PSeedNodeSnapshot.run.hosts=3f3cu2yw7u457ztq.onion:8000, 723ljisnynbtdohi.onion:8000, fl3mmribyxgrv63c.onion:8000 -P2PSeedNodeSnapshot.run.torProxyPort=9062 - -#P2PMarketStats Metric -P2PMarketStats.enabled=true -P2PMarketStats.run.interval=37 -P2PMarketStats.run.hosts=ef5qnzx6znifo3df.onion:8000 -P2PMarketStats.run.torProxyPort=9063 - -#PriceNodeStats Metric -PriceNodeStats.enabled=true -PriceNodeStats.run.interval=42 -PriceNodeStats.run.hosts=http://5bmpx76qllutpcyp.onion, http://xc3nh4juf2hshy7e.onion, http://44mgyoe2b6oqiytt.onion, http://62nvujg5iou3vu3i.onion, http://ceaanhbvluug4we6.onion - -#MarketStats Metric -MarketStats.enabled=true -MarketStats.run.interval=191 - -## Reporters are configured via a set of properties as well. -## -## In contrast to Metrics, Reporters do not have a minimal set of properties. - -#GraphiteReporter -GraphiteReporter.serviceUrl=k6evlhg44acpchtc.onion:2003 - -``` - -## Run - -The distribution ships with a systemd .service file. Validate/change the executable/config paths within the shipped `bisq-monitor.service` file and copy/move the file to your systemd directory (something along `/usr/lib/systemd/system/`). Now you can control your *Monitor Node* via the usual systemd start/stop commands - -``` -systemctl start bisq-monitor.service -systemctl stop bisq-monitor.service -``` -and -``` -systemctl enable bisq-monitor.service -``` - -You can reload the configuration without restarting the service by using - -``` -systemctl reload bisq-monitor.service -``` - -Follow the logs created by the service by inspecting - -``` -journalctl --unit bisq-monitor --follow -``` - -# Monitoring Service - -A typical monitoring service consists of a [Graphite](https://graphiteapp.org/) and a [Grafana](https://grafana.com/) instance. -Both are available via Docker-containers. - -## Setting up Graphite - -### Install - -For a docker setup, use - -``` -docker run -d --name graphite --restart=always -p 2003:2003 -p 8080:8080 graphiteapp/graphite-statsd -``` - -- Port 2003 is used for the [plaintext protocol](https://graphite.readthedocs.io/en/latest/feeding-carbon.html#the-plaintext-protocol) mentioned above -- Port 8080 offers an API for user interfaces. - -more information can be found [here](https://graphite.readthedocs.io/en/latest/install.html) - -### Configuration - -For configuration, you must adapt the whisper database schema to suit your needs. First, stop your docker container by running - -``` -docker stop graphite -``` - -Find your config files within the `Source` directory stated in - -``` -docker inspect graphite | grep -C 2 graphite/conf\", -``` - -Edit `storage-schemas.conf` so that the frequency of your incoming data (configured in the monitor configs `interval`) is matched. For example, insert -``` -[bisq] -pattern = ^bisq.* -retentions = 10s:1h,5m:31d,30m:2y,1h:5y -``` -before the `[default...` blocks of the file. This basically says, that every incoming set of data reflects 5 minutes of the time series. Furthermore, every 30 minutes, the data is compressed and thus, takes less memory as it is kept for 2 years. - -Further, edit `storage-aggregation.conf` to configure how your data is compressed. For example, insert -``` -[bisq] -pattern=^bisq.* -xFilesFactor = 0 -aggregationMethod = average -``` -before the `[default...` blocks of the file. With this configuration, whenever data is aggregated, the `average` data is made available given that at least `0%` of the data points (i.e. floor(30 / 5 * 40%) = 2 data points) exist. Otherwise, the aggregated data is dropped. Since we start the first hour with a frequency of 10s but only supply data every 4 to 6 minutes, our aggregated values would get dropped. - -*Please note, that I have not been able to get the whole thing to work without the 10s:1h part yet* - -Finally, update the database. For doing that, go to the storage directory of graphite, the `Source` directory stated in -``` -docker inspect graphite | grep -C 2 graphite/conf\", -``` -Once there, you have two options: -- delete the whisper directory -``` -rm -r whisper -``` -- update the database by doing -``` -find ./ -type f -name '*.wsp' -exec whisper-resize.py --nobackup {} 10s:1h 5m:31d 30m:2y 1h:5y \; -``` - -and finally, restart your graphite container: -``` -docker start graphite -``` - - -Other than that, there is no further configuration necessary. However, you might change your iptables/firewalls to not let anyone access your Graphite instance from the outside. - -### Backup your data - -The metric data is kept in the `Source` directory stated in -``` -docker inspect graphite | grep -C 2 graphite/conf\", -``` -ready to be backed up regularly. - -## Setting up Grafana - -### Install - -For a docker setup, use - -``` -docker run -d --name=grafana -p 3000:3000 grafana/grafana -``` - -- Port 3000 offers the web interface - -more information can be found [here](https://grafana.com/grafana/download?platform=docker) - -### Configuration - -- Once you have Grafana up and running, go to the *Data Source* configuration tab. -- Once there click *Add data source* and select *Graphite*. -- In the HTTP section enter the IP address of your graphite docker container and the port `8080` (as we have configured before). E.g. `http://172.170.1:8080` -- Select `Server (default)` as an *Access* method and hit *Save & Test*. - -You should be all set. You can now proceed to add Dashboards, Panels and finally display the prettiest Graphs you can think of. -A working connection to Graphite should let you add your data series in a *Graph*s *Metrics* tab in a pretty intuitive way. - -- Optional: hide your Grafana instance behind a reverse proxy like nginx and add some TLS. -- Optional: make your Grafana instance accessible via a Tor hidden service. - -### Backup your data - -Grafana stores every dashboard as a JSON model. This model can be accessed (copied/restored) within the dashboard's settings and its *JSON Model* tab. Do with the data whatever you want. diff --git a/monitor/bisq-monitor.service b/monitor/bisq-monitor.service deleted file mode 100644 index 892c69ae53b..00000000000 --- a/monitor/bisq-monitor.service +++ /dev/null @@ -1,16 +0,0 @@ -[Unit] -Description=Bisq network monitor -After=network.target - -[Service] -WorkingDirectory=~ -Environment="JAVA_OPTS='-Xmx500M'" -ExecStart=/home/bisq/bisq/bisq-monitor /home/bisq/monitor.properties -ExecReload=/bin/kill -USR1 $MAINPID -Restart=on-failure - -User=bisq -Group=bisq - -[Install] -WantedBy=multi-user.target diff --git a/monitor/collectd.conf b/monitor/collectd.conf deleted file mode 100644 index f6106508b11..00000000000 --- a/monitor/collectd.conf +++ /dev/null @@ -1,136 +0,0 @@ -Hostname "__ONION_ADDRESS__" -Interval 30 - -LoadPlugin syslog - - LogLevel info - - -LoadPlugin cpu -LoadPlugin df -LoadPlugin disk -LoadPlugin fhcount -LoadPlugin interface -LoadPlugin java -LoadPlugin load -LoadPlugin memory -LoadPlugin processes -LoadPlugin swap -LoadPlugin write_graphite - - - ReportByCpu true - ValuesPercentage true - - - - MountPoint "/" - - - - Disk "/[hs]da/" - - - - ValuesAbsolute false - ValuesPercentage true - - - - Interface "eth0" - - - - JVMArg "-verbose:jni" - JVMArg "-Djava.class.path=/usr/share/collectd/java/collectd-api.jar:/usr/share/collectd/java/generic-jmx.jar" - - LoadPlugin "org.collectd.java.GenericJMX" - - # Generic heap/nonheap memory usage. - - ObjectName "java.lang:type=Memory" - #InstanceFrom "" - InstancePrefix "memory" - - # Creates four values: committed, init, max, used - - Type "memory" - #InstancePrefix "" - #InstanceFrom "" - Table true - Attribute "HeapMemoryUsage" - InstancePrefix "heap-" - - - # Creates four values: committed, init, max, used - - Type "memory" - #InstancePrefix "" - #InstanceFrom "" - Table true - Attribute "NonHeapMemoryUsage" - InstancePrefix "nonheap-" - - - - # Memory usage by memory pool. - - ObjectName "java.lang:type=MemoryPool,*" - InstancePrefix "memory_pool-" - InstanceFrom "name" - - - Type "memory" - #InstancePrefix "" - #InstanceFrom "" - Table true - Attribute "Usage" - - - - - ServiceURL "service:jmx:rmi:///jndi/rmi://localhost:6969/jmxrmi" - Collect "memory_pool" - Collect "memory" - - - # See /usr/share/doc/collectd/examples/GenericJMX.conf - # for an example config. - - - -# -# ReportRelative true -# - -# -# ValuesAbsolute true -# ValuesPercentage false -# - -# -# Process "name" -# ProcessMatch "foobar" "/usr/bin/perl foobar\\.pl.*" -# - -# -# ReportByDevice false -# ReportBytes true -# - - - - Host "127.0.0.1" - Port "2003" - Protocol "tcp" - ReconnectInterval 0 - LogSendErrors false - Prefix "servers." - StoreRates true - AlwaysAppendDS false - EscapeCharacter "_" - SeparateInstances false - PreserveSeparator false - DropDuplicateFields false - - diff --git a/monitor/install_collectd_debian.sh b/monitor/install_collectd_debian.sh deleted file mode 100755 index 83bdf339db7..00000000000 --- a/monitor/install_collectd_debian.sh +++ /dev/null @@ -1,75 +0,0 @@ -#!/bin/bash -set -e - -echo "[*] Bisq Server Monitoring installation script" - -##### change paths if necessary for your system -BISQ_REPO_URL=https://raw.githubusercontent.com/bisq-network/bisq -BISQ_REPO_TAG=master -ROOT_USER=root -ROOT_GROUP=root -ROOT_HOME=~root -ROOT_PKG=(nginx collectd openssl) - -SYSTEMD_ENV_HOME=/etc/default - -##### - -echo "[*] Gathering information" -read -p "Please provide the onion address of your service (eg. 3f3cu2yw7u457ztq): " onionaddress - -echo "[*] Updating apt repo sources" -sudo -H -i -u "${ROOT_USER}" DEBIAN_FRONTEND=noninteractive apt-get update -q - -echo "[*] Upgrading OS packages" -sudo -H -i -u "${ROOT_USER}" DEBIAN_FRONTEND=noninteractive apt-get upgrade -qq -y - -echo "[*] Installing base packages" -sudo -H -i -u "${ROOT_USER}" DEBIAN_FRONTEND=noninteractive apt-get install -qq -y ${ROOT_PKG[@]} - -echo "[*] Preparing Bisq init script for monitoring" -# remove stuff it it is there already -for file in "${SYSTEMD_ENV_HOME}/bisq.env" "${SYSTEMD_ENV_HOME}/bisq-pricenode.env" -do - if [ -f "$file" ];then - sudo -H -i -u "${ROOT_USER}" sed -i -e 's/-Dcom.sun.management.jmxremote //g' -e 's/-Dcom.sun.management.jmxremote.local.only=true//g' -e 's/ -Dcom.sun.management.jmxremote.host=127.0.0.1//g' -e 's/ -Dcom.sun.management.jmxremote.port=6969//g' -e 's/ -Dcom.sun.management.jmxremote.rmi.port=6969//g' -e 's/ -Dcom.sun.management.jmxremote.ssl=false//g' -e 's/ -Dcom.sun.management.jmxremote.authenticate=false//g' "${file}" - sudo -H -i -u "${ROOT_USER}" sed -i -e '/JAVA_OPTS/ s/"$/ -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.local.only=true -Dcom.sun.management.jmxremote.host=127.0.0.1 -Dcom.sun.management.jmxremote.port=6969 -Dcom.sun.management.jmxremote.rmi.port=6969 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false"/' "${file}" - fi -done - -echo "[*] Seeding entropy from /dev/urandom" -sudo -H -i -u "${ROOT_USER}" /bin/sh -c "head -1500 /dev/urandom > ${ROOT_HOME}/.rnd" -echo "[*] Installing Nginx config" -sudo -H -i -u "${ROOT_USER}" openssl req -x509 -nodes -newkey rsa:2048 -days 3000 -keyout /etc/nginx/cert.key -out /etc/nginx/cert.crt -subj="/O=Bisq/OU=Bisq Infrastructure/CN=$onionaddress" -curl -s "${BISQ_REPO_URL}/${BISQ_REPO_TAG}/monitor/nginx.conf" > /tmp/nginx.conf -sudo -H -i -u "${ROOT_USER}" install -c -o "${ROOT_USER}" -g "${ROOT_GROUP}" -m 644 /tmp/nginx.conf /etc/nginx/nginx.conf - -echo "[*] Installing collectd config" -curl -s "${BISQ_REPO_URL}/${BISQ_REPO_TAG}/monitor/collectd.conf" > /tmp/collectd.conf -sudo -H -i -u "${ROOT_USER}" install -c -o "${ROOT_USER}" -g "${ROOT_GROUP}" -m 644 /tmp/collectd.conf /etc/collectd/collectd.conf -sudo -H -i -u "${ROOT_USER}" sed -i -e "s/__ONION_ADDRESS__/$onionaddress/" /etc/collectd/collectd.conf - -echo "[*] Updating systemd daemon configuration" -sudo -H -i -u "${ROOT_USER}" systemctl daemon-reload -sudo -H -i -u "${ROOT_USER}" systemctl enable nginx.service -sudo -H -i -u "${ROOT_USER}" systemctl enable collectd.service - -echo "[*] Restarting services" -set +e -service bisq status >/dev/null 2>&1 -[ $? != 4 ] && sudo -H -i -u "${ROOT_USER}" systemctl restart bisq.service -service bisq-pricenode status >/dev/null 2>&1 -[ $? != 4 ] && sudo -H -i -u "${ROOT_USER}" systemctl restart bisq-pricenode.service -sudo -H -i -u "${ROOT_USER}" systemctl restart nginx.service -sudo -H -i -u "${ROOT_USER}" systemctl restart collectd.service - -echo '[*] Done!' - -echo ' ' -echo '[*] Report this certificate to the monitoring team!' -echo '----------------------------------------------------------------' -echo "Server: $onionaddress" -echo ' ' -cat /etc/nginx/cert.crt -echo '----------------------------------------------------------------' -echo ' ' diff --git a/monitor/nginx.conf b/monitor/nginx.conf deleted file mode 100644 index fc1a962f148..00000000000 --- a/monitor/nginx.conf +++ /dev/null @@ -1,28 +0,0 @@ -load_module /usr/lib/nginx/modules/ngx_stream_module.so; - -worker_processes 1; - -events { - worker_connections 1024; -} - -stream { - - log_format basic '$remote_addr [$time_local] ' - '$protocol Status $status Sent $bytes_sent Received $bytes_received ' - 'Time $session_time'; - - error_log syslog:server=unix:/dev/log; - access_log syslog:server=unix:/dev/log basic; - - server { - listen 127.0.0.1:2003; - proxy_pass monitor.bisq.network:2002; - proxy_ssl on; - - proxy_ssl_certificate /etc/nginx/cert.crt; - proxy_ssl_certificate_key /etc/nginx/cert.key; - - proxy_ssl_session_reuse on; - } -} diff --git a/monitor/src/main/java/bisq/monitor/AvailableTor.java b/monitor/src/main/java/bisq/monitor/AvailableTor.java deleted file mode 100644 index 0c79ec48e39..00000000000 --- a/monitor/src/main/java/bisq/monitor/AvailableTor.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * This file is part of Bisq. - * - * Bisq is free software: you can redistribute it and/or modify it - * under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or (at - * your option) any later version. - * - * Bisq is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public - * License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with Bisq. If not, see . - */ - -package bisq.monitor; - -import bisq.network.p2p.network.TorMode; - -import org.berndpruenster.netlayer.tor.Tor; - -import java.io.File; - -/** - * This class uses an already defined Tor via Tor.getDefault() - * - * @author Florian Reimair - * - */ -public class AvailableTor extends TorMode { - - private final String hiddenServiceDirectory; - - public AvailableTor(File torWorkingDirectory, String hiddenServiceDirectory) { - super(torWorkingDirectory); - - this.hiddenServiceDirectory = hiddenServiceDirectory; - } - - @Override - public Tor getTor() { - return Tor.getDefault(); - } - - @Override - public String getHiddenServiceDirectory() { - return hiddenServiceDirectory; - } - -} diff --git a/monitor/src/main/java/bisq/monitor/Configurable.java b/monitor/src/main/java/bisq/monitor/Configurable.java deleted file mode 100644 index 6280f02255b..00000000000 --- a/monitor/src/main/java/bisq/monitor/Configurable.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * This file is part of Bisq. - * - * Bisq is free software: you can redistribute it and/or modify it - * under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or (at - * your option) any later version. - * - * Bisq is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public - * License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with Bisq. If not, see . - */ - -package bisq.monitor; - -import java.util.Properties; - -/** - * Does some pre-computation for a configurable class. - * - * @author Florian Reimair - */ -public abstract class Configurable { - - protected Properties configuration = new Properties(); - - private String name; - - /** - * Filters all java properties starting with {@link Configurable#getName()} of - * the class and makes them available. Does NOT parse the content of - * the properties! - *

- * For example, if the implementing class sets its name (using - * {@link Configurable#setName(String)}) to MyName, the list of - * properties is scanned for properties starting with MyName. - * Matching lines are made available to the class without the prefix. For - * example, a property MyName.answer=42 is made available as - * configuration.getProperty("answer") resulting in - * 42. - * - * @param properties a set of configuration properties - */ - public void configure(final Properties properties) { - // only configure the Properties which belong to us - final Properties myProperties = new Properties(); - properties.forEach((k, v) -> { - String key = (String) k; - if (key.startsWith(getName())) - myProperties.put(key.substring(key.indexOf(".") + 1), v); - }); - - // configure all properties that belong to us - this.configuration = myProperties; - } - - protected String getName() { - return name; - } - - /** - * Set the name used to filter through configuration properties. See - * {@link Configurable#configure(Properties)}. - * - * @param name the name of the configurable - */ - protected void setName(String name) { - this.name = name; - } -} diff --git a/monitor/src/main/java/bisq/monitor/Metric.java b/monitor/src/main/java/bisq/monitor/Metric.java deleted file mode 100644 index 08598e1e9cf..00000000000 --- a/monitor/src/main/java/bisq/monitor/Metric.java +++ /dev/null @@ -1,147 +0,0 @@ -/* - * This file is part of Bisq. - * - * Bisq is free software: you can redistribute it and/or modify it - * under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or (at - * your option) any later version. - * - * Bisq is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public - * License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with Bisq. If not, see . - */ - -package bisq.monitor; - -import bisq.common.app.Version; -import bisq.common.util.Utilities; - -import java.util.Properties; -import java.util.Random; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.ScheduledFuture; -import java.util.concurrent.ScheduledThreadPoolExecutor; -import java.util.concurrent.TimeUnit; - -import lombok.extern.slf4j.Slf4j; - -import static bisq.common.config.Config.BASE_CURRENCY_NETWORK; - -/** - * Starts a Metric (in its own {@link Thread}), manages its properties and shuts - * it down gracefully. Furthermore, configuration updates and execution are done - * in a thread-save manner. Implementing classes only have to implement the - * {@link Metric#execute()} method. - * - * @author Florian Reimair - */ -@Slf4j -public abstract class Metric extends Configurable implements Runnable { - - private static final String INTERVAL = "run.interval"; - private static ScheduledExecutorService executor; - protected final Reporter reporter; - private ScheduledFuture scheduler; - - /** - * disable execution - */ - private void disable() { - if (scheduler != null) - scheduler.cancel(false); - } - - /** - * enable execution - */ - private void enable() { - scheduler = executor.scheduleWithFixedDelay(this, new Random().nextInt(60), - Long.parseLong(configuration.getProperty(INTERVAL)), TimeUnit.SECONDS); - } - - /** - * Constructor. - */ - protected Metric(Reporter reporter) { - - this.reporter = reporter; - - setName(this.getClass().getSimpleName()); - - if (executor == null) { - executor = new ScheduledThreadPoolExecutor(6); - } - } - - boolean enabled() { - if (scheduler != null) - return !scheduler.isCancelled(); - else - return false; - } - - @Override - public void configure(final Properties properties) { - synchronized (this) { - log.info("{} (re)loading config...", getName()); - super.configure(properties); - reporter.configure(properties); - - Version.setBaseCryptoNetworkId(Integer.parseInt(properties.getProperty("System." + BASE_CURRENCY_NETWORK, "1"))); // defaults to BTC_TESTNET - - // decide whether to enable or disable the task - if (configuration.isEmpty() || !configuration.getProperty("enabled", "false").equals("true") - || !configuration.containsKey(INTERVAL)) { - disable(); - - // some informative log output - if (configuration.isEmpty()) - log.error("{} is not configured at all. Will not run.", getName()); - else if (!configuration.getProperty("enabled", "false").equals("true")) - log.info("{} is deactivated. Will not run.", getName()); - else if (!configuration.containsKey(INTERVAL)) - log.error("{} is missing mandatory '" + INTERVAL + "' property. Will not run.", getName()); - else - log.error("{} is mis-configured. Will not run.", getName()); - } else if (!enabled() && configuration.getProperty("enabled", "false").equals("true")) { - // check if this Metric got activated after being disabled. - // if so, resume execution - enable(); - log.info("{} got activated. Starting up.", getName()); - } - } - } - - @Override - public void run() { - try { - Thread.currentThread().setName("Metric: " + getName()); - - // execute all the things - synchronized (this) { - log.info("{} started", getName()); - execute(); - log.info("{} done", getName()); - } - } catch (Throwable e) { - log.error("A metric misbehaved!", e); - } - } - - /** - * Gets scheduled repeatedly. - */ - protected abstract void execute(); - - /** - * initiate an orderly shutdown on all metrics. Blocks until all metrics are - * shut down or after one minute. - */ - public static void haltAllMetrics() { - Utilities.shutdownAndAwaitTermination(executor, 2, TimeUnit.MINUTES); - } -} diff --git a/monitor/src/main/java/bisq/monitor/Monitor.java b/monitor/src/main/java/bisq/monitor/Monitor.java deleted file mode 100644 index ea6b0db3619..00000000000 --- a/monitor/src/main/java/bisq/monitor/Monitor.java +++ /dev/null @@ -1,182 +0,0 @@ -/* - * This file is part of Bisq. - * - * Bisq is free software: you can redistribute it and/or modify it - * under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or (at - * your option) any later version. - * - * Bisq is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public - * License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with Bisq. If not, see . - */ - -package bisq.monitor; - -import bisq.monitor.metric.MarketStats; -import bisq.monitor.metric.P2PMarketStats; -import bisq.monitor.metric.P2PNetworkLoad; -import bisq.monitor.metric.P2PRoundTripTime; -import bisq.monitor.metric.P2PSeedNodeSnapshot; -import bisq.monitor.metric.PriceNodeStats; -import bisq.monitor.metric.TorHiddenServiceStartupTime; -import bisq.monitor.metric.TorRoundTripTime; -import bisq.monitor.metric.TorStartupTime; -import bisq.monitor.reporter.ConsoleReporter; -import bisq.monitor.reporter.GraphiteReporter; - -import bisq.common.app.Capabilities; -import bisq.common.app.Capability; - -import org.berndpruenster.netlayer.tor.NativeTor; -import org.berndpruenster.netlayer.tor.Tor; - -import java.io.File; -import java.io.FileInputStream; - -import java.util.ArrayList; -import java.util.List; -import java.util.Properties; - -import lombok.extern.slf4j.Slf4j; - -import static com.google.common.base.Preconditions.checkNotNull; - - - -import sun.misc.Signal; - -/** - * Monitor executable for the Bisq network. - * - * @author Florian Reimair - */ -@Slf4j -public class Monitor { - - public static final File TOR_WORKING_DIR = new File("monitor/work/monitor-tor"); - private static String[] args = {}; - - public static void main(String[] args) throws Throwable { - Monitor.args = args; - new Monitor().start(); - } - - /** - * A list of all active {@link Metric}s - */ - private final List metrics = new ArrayList<>(); - - /** - * Starts up all configured Metrics. - * - * @throws Throwable in case something goes wrong - */ - private void start() throws Throwable { - - // start Tor - Tor.setDefault(new NativeTor(TOR_WORKING_DIR, null, null, false)); - - //noinspection deprecation,deprecation,deprecation,deprecation,deprecation,deprecation,deprecation,deprecation - 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.REFUND_AGENT, - Capability.MEDIATION, - Capability.TRADE_STATISTICS_3); - - // assemble Metrics - // - create reporters - Reporter graphiteReporter = new GraphiteReporter(); - - // only use ConsoleReporter if requested (for debugging for example) - Properties properties = getProperties(); - if ("true".equals(properties.getProperty("System.useConsoleReporter", "false"))) - graphiteReporter = new ConsoleReporter(); - - // - add available metrics with their reporters - metrics.add(new TorStartupTime(graphiteReporter)); - metrics.add(new TorRoundTripTime(graphiteReporter)); - metrics.add(new TorHiddenServiceStartupTime(graphiteReporter)); - metrics.add(new P2PRoundTripTime(graphiteReporter)); - metrics.add(new P2PNetworkLoad(graphiteReporter)); - metrics.add(new P2PSeedNodeSnapshot(graphiteReporter)); - metrics.add(new P2PMarketStats(graphiteReporter)); - metrics.add(new PriceNodeStats(graphiteReporter)); - metrics.add(new MarketStats(graphiteReporter)); - - // prepare configuration reload - // Note that this is most likely only work on Linux - Signal.handle(new Signal("USR1"), signal -> { - try { - configure(); - } catch (Exception e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - }); - - // configure Metrics - // - which also starts the metrics if appropriate - configure(); - - // exit Metrics gracefully on shutdown - Runtime.getRuntime().addShutdownHook(new Thread(() -> { - // set the name of the Thread for debugging purposes - log.info("system shutdown initiated"); - - log.info("shutting down active metrics..."); - Metric.haltAllMetrics(); - - try { - log.info("shutting down tor..."); - Tor tor = Tor.getDefault(); - checkNotNull(tor, "tor must not be null"); - tor.shutdown(); - } catch (Throwable ignore) { - } - - log.info("system halt"); - }, "Monitor Shutdown Hook ") - ); - } - - /** - * Reload the configuration from disk. - * - * @throws Exception if something goes wrong - */ - private void configure() throws Exception { - Properties properties = getProperties(); - for (Metric current : metrics) - current.configure(properties); - } - - /** - * Overloads a default set of properties with a file if given - * - * @return a set of properties - * @throws Exception in case something goes wrong - */ - private Properties getProperties() throws Exception { - Properties result = new Properties(); - - // if we have a config file load the config file, else, load the default config - // from the resources - if (args.length > 0) - result.load(new FileInputStream(args[0])); - else - result.load(Monitor.class.getClassLoader().getResourceAsStream("metrics.properties")); - - return result; - } -} diff --git a/monitor/src/main/java/bisq/monitor/OnionParser.java b/monitor/src/main/java/bisq/monitor/OnionParser.java deleted file mode 100644 index 58f186f068a..00000000000 --- a/monitor/src/main/java/bisq/monitor/OnionParser.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * This file is part of Bisq. - * - * Bisq is free software: you can redistribute it and/or modify it - * under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or (at - * your option) any later version. - * - * Bisq is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public - * License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with Bisq. If not, see . - */ - -package bisq.monitor; - -import bisq.network.p2p.NodeAddress; - -import java.net.MalformedURLException; -import java.net.URL; - -/** - * Helper for parsing and pretty printing onion addresses. - * - * @author Florian Reimair - */ -public class OnionParser { - - public static NodeAddress getNodeAddress(final String current) throws MalformedURLException { - String nodeAddress = current.trim(); - if (!nodeAddress.startsWith("http://")) - nodeAddress = "http://" + nodeAddress; - URL tmp = new URL(nodeAddress); - return new NodeAddress(tmp.getHost(), tmp.getPort() > 0 ? tmp.getPort() : 80); - } - - public static String prettyPrint(final NodeAddress host) { - return host.getHostNameWithoutPostFix(); - } - - public static String prettyPrint(String host) throws MalformedURLException { - return prettyPrint(getNodeAddress(host)); - } -} diff --git a/monitor/src/main/java/bisq/monitor/Reporter.java b/monitor/src/main/java/bisq/monitor/Reporter.java deleted file mode 100644 index 5c0202e7f38..00000000000 --- a/monitor/src/main/java/bisq/monitor/Reporter.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * This file is part of Bisq. - * - * Bisq is free software: you can redistribute it and/or modify it - * under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or (at - * your option) any later version. - * - * Bisq is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public - * License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with Bisq. If not, see . - */ - -package bisq.monitor; - -import java.util.Map; - -/** - * Reports findings to a specific service/file/place using the proper means to - * do so. - * - * @author Florian Reimair - */ -public abstract class Reporter extends Configurable { - - protected Reporter() { - setName(this.getClass().getSimpleName()); - } - - /** - * Report our findings. - * - * @param value the value to report - */ - public abstract void report(long value); - - /** - * Report our findings - * - * @param value the value to report - * @param prefix a common prefix to be included in the tag name - */ - public abstract void report(long value, String prefix); - - /** - * Report our findings. - * - * @param values Map - */ - public abstract void report(Map values); - - /** - * Report our findings. - * - * @param values Map - * @param prefix for example "torStartupTime" - */ - public abstract void report(Map values, String prefix); - - /** - * Report our findings one by one. - * - * @param key the metric name - * @param value the value to report - * @param timestamp a unix timestamp in milliseconds - * @param prefix for example "torStartupTime" - */ - public abstract void report(String key, String value, String timestamp, String prefix); - -} diff --git a/monitor/src/main/java/bisq/monitor/StatisticsHelper.java b/monitor/src/main/java/bisq/monitor/StatisticsHelper.java deleted file mode 100644 index c73c904ff21..00000000000 --- a/monitor/src/main/java/bisq/monitor/StatisticsHelper.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * This file is part of Bisq. - * - * Bisq is free software: you can redistribute it and/or modify it - * under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or (at - * your option) any later version. - * - * Bisq is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public - * License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with Bisq. If not, see . - */ - -package bisq.monitor; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.LongSummaryStatistics; -import java.util.Map; - -/** - * Calculates average, max, min, p25, p50, p75 off of a list of samples and - * throws in the sample size for good measure. - * - * @author Florian Reimair - */ -public class StatisticsHelper { - - public static Map process(Collection input) { - - List samples = new ArrayList<>(input); - - // aftermath - Collections.sort(samples); - - // - average, max, min , sample size - LongSummaryStatistics statistics = samples.stream().mapToLong(val -> val).summaryStatistics(); - - Map results = new HashMap<>(); - results.put("average", String.valueOf(Math.round(statistics.getAverage()))); - results.put("max", String.valueOf(statistics.getMax())); - results.put("min", String.valueOf(statistics.getMin())); - results.put("sampleSize", String.valueOf(statistics.getCount())); - - // - p25, median, p75 - Integer[] percentiles = new Integer[] { 25, 50, 75 }; - for (Integer percentile : percentiles) { - double rank = statistics.getCount() * percentile / 100.0; - Long percentileValue; - if (samples.size() <= rank + 1) - percentileValue = samples.get(samples.size() - 1); - else if (Math.floor(rank) == rank) - percentileValue = samples.get((int) rank); - else - percentileValue = Math.round(samples.get((int) Math.floor(rank)) - + (samples.get((int) (Math.floor(rank) + 1)) - samples.get((int) Math.floor(rank))) - / (rank - Math.floor(rank))); - results.put("p" + percentile, String.valueOf(percentileValue)); - } - - return results; - } -} diff --git a/monitor/src/main/java/bisq/monitor/ThreadGate.java b/monitor/src/main/java/bisq/monitor/ThreadGate.java deleted file mode 100644 index 60fa1586e3b..00000000000 --- a/monitor/src/main/java/bisq/monitor/ThreadGate.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * This file is part of Bisq. - * - * Bisq is free software: you can redistribute it and/or modify it - * under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or (at - * your option) any later version. - * - * Bisq is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public - * License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with Bisq. If not, see . - */ - -package bisq.monitor; - -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - -import lombok.extern.slf4j.Slf4j; - -/** - * Gate pattern to help with thread synchronization - * - * @author Florian Reimair - */ -@Slf4j -public class ThreadGate { - - private CountDownLatch lock = new CountDownLatch(0); - - /** - * Make everyone wait until the gate is open again. - */ - public void engage() { - lock = new CountDownLatch(1); - } - - /** - * Make everyone wait until the gate is open again. - * - * @param numberOfLocks how often the gate has to be unlocked until the gate - * opens. - */ - public void engage(int numberOfLocks) { - lock = new CountDownLatch(numberOfLocks); - } - - /** - * Wait for the gate to be opened. Blocks until the gate is open again. Returns - * immediately if the gate is already open. - */ - public synchronized void await() { - while (lock.getCount() > 0) - try { - if (!lock.await(60, TimeUnit.SECONDS)) { - log.warn("timeout occurred!"); - break; // break the loop - } - } catch (InterruptedException ignore) { - } - } - - /** - * Open the gate and let everyone proceed with their execution. - */ - public void proceed() { - lock.countDown(); - } - - /** - * Open the gate with no regards on how many locks are still in place. - */ - public void unlock() { - while (lock.getCount() > 0) - lock.countDown(); - } -} diff --git a/monitor/src/main/java/bisq/monitor/metric/MarketStats.java b/monitor/src/main/java/bisq/monitor/metric/MarketStats.java deleted file mode 100644 index f54c862446c..00000000000 --- a/monitor/src/main/java/bisq/monitor/metric/MarketStats.java +++ /dev/null @@ -1,100 +0,0 @@ -/* - * This file is part of Bisq. - * - * bisq is free software: you can redistribute it and/or modify it - * under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or (at - * your option) any later version. - * - * bisq is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public - * License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with bisq. If not, see . - */ - -package bisq.monitor.metric; - -import bisq.monitor.Metric; -import bisq.monitor.Reporter; - -import java.net.URL; -import java.net.URLConnection; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStreamReader; - -import java.util.Arrays; -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.TimeUnit; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import lombok.extern.slf4j.Slf4j; - -/** - * Uses the markets API to retrieve market volume data. - * - * @author Florian Reimair - * - */ -@Slf4j -public class MarketStats extends Metric { - private static final String MARKETS_BISQ_NETWORK = "https://markets.bisq.network"; - // poor mans JSON parser - private final Pattern marketPattern = Pattern.compile("\"market\" ?: ?\"([a-z_]+)\""); - private final Pattern amountPattern = Pattern.compile("\"amount\" ?: ?\"([\\d\\.]+)\""); - private final Pattern volumePattern = Pattern.compile("\"volume\" ?: ?\"([\\d\\.]+)\""); - private final Pattern timestampPattern = Pattern.compile("\"trade_date\" ?: ?([\\d]+)"); - - private Long lastRun = TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis() - TimeUnit.MINUTES.toMillis(15)); - - public MarketStats(Reporter reporter) { - super(reporter); - } - - @Override - protected void execute() { - try { - // for each configured host - Map result = new HashMap<>(); - - // assemble query - long now = TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis()); - String query = "/api/trades?format=json&market=all×tamp_from=" + lastRun + "×tamp_to=" + now; - lastRun = now; // thought about adding 1 second but what if a trade is done exactly in this one second? - - // connect - URLConnection connection = new URL(MARKETS_BISQ_NETWORK + query).openConnection(); - - // prepare to receive data - BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream())); - - String line, all = ""; - while ((line = in.readLine()) != null) - all += ' ' + line; - in.close(); - - Arrays.stream(all.substring(0, all.length() - 2).split("}")).forEach(trade -> { - Matcher market = marketPattern.matcher(trade); - Matcher amount = amountPattern.matcher(trade); - Matcher timestamp = timestampPattern.matcher(trade); - market.find(); - if (market.group(1).endsWith("btc")) { - amount = volumePattern.matcher(trade); - } - amount.find(); - timestamp.find(); - reporter.report("volume." + market.group(1), amount.group(1), timestamp.group(1), getName()); - }); - } catch (IllegalStateException ignore) { - // no match found - } catch (IOException e) { - e.printStackTrace(); - } - } -} diff --git a/monitor/src/main/java/bisq/monitor/metric/P2PMarketStats.java b/monitor/src/main/java/bisq/monitor/metric/P2PMarketStats.java deleted file mode 100644 index 368e9cb03c1..00000000000 --- a/monitor/src/main/java/bisq/monitor/metric/P2PMarketStats.java +++ /dev/null @@ -1,282 +0,0 @@ -/* - * This file is part of Bisq. - * - * bisq is free software: you can redistribute it and/or modify it - * under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or (at - * your option) any later version. - * - * bisq is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public - * License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with bisq. If not, see . - */ - -package bisq.monitor.metric; - -import bisq.monitor.Reporter; - -import bisq.core.offer.OfferUtil; -import bisq.core.offer.bisq_v1.OfferPayload; - -import bisq.network.p2p.NodeAddress; -import bisq.network.p2p.network.Connection; -import bisq.network.p2p.peers.getdata.messages.GetDataResponse; -import bisq.network.p2p.peers.getdata.messages.PreliminaryGetDataRequest; -import bisq.network.p2p.storage.payload.ProtectedStorageEntry; -import bisq.network.p2p.storage.payload.ProtectedStoragePayload; - -import bisq.common.proto.network.NetworkEnvelope; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Random; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -import java.util.stream.Collectors; - -import lombok.extern.slf4j.Slf4j; - -import static com.google.common.base.Preconditions.checkNotNull; - -/** - * Demo Stats metric derived from the OfferPayload messages we get from the seed nodes - * - * @author Florian Reimair - */ -@Slf4j -public class P2PMarketStats extends P2PSeedNodeSnapshotBase { - final Map> versionBucketsPerHost = new ConcurrentHashMap<>(); - final Map> offerVolumeBucketsPerHost = new ConcurrentHashMap<>(); - final Map>> offerVolumeDistributionBucketsPerHost = new ConcurrentHashMap<>(); - final Map>> offersPerTraderBucketsPerHost = new ConcurrentHashMap<>(); - final Map>> volumePerTraderBucketsPerHost = new ConcurrentHashMap<>(); - - /** - * Efficient way to aggregate numbers. - */ - private static class Aggregator { - private long value = 0; - - synchronized long value() { - return value; - } - - synchronized void increment() { - value++; - } - - synchronized void add(long amount) { - value += amount; - } - } - - private abstract static class OfferStatistics extends Statistics { - @Override - public synchronized void log(Object message) { - if (message instanceof OfferPayload) { - OfferPayload currentMessage = (OfferPayload) message; - // For logging different data types - String market = currentMessage.getDirection() + "." + currentMessage.getBaseCurrencyCode() + "_" + currentMessage.getCounterCurrencyCode(); - - process(market, currentMessage); - } - } - - abstract void process(String market, OfferPayload currentMessage); - } - - private class OfferCountStatistics extends OfferStatistics { - - @Override - void process(String market, OfferPayload currentMessage) { - buckets.putIfAbsent(market, new Aggregator()); - buckets.get(market).increment(); - } - } - - private class OfferVolumeStatistics extends OfferStatistics { - - @Override - void process(String market, OfferPayload currentMessage) { - buckets.putIfAbsent(market, new Aggregator()); - buckets.get(market).add(currentMessage.getAmount()); - } - } - - private class OfferVolumeDistributionStatistics extends OfferStatistics> { - - @Override - void process(String market, OfferPayload currentMessage) { - buckets.putIfAbsent(market, new ArrayList<>()); - buckets.get(market).add(currentMessage.getAmount()); - } - } - - private class OffersPerTraderStatistics extends OfferStatistics> { - - @Override - void process(String market, OfferPayload currentMessage) { - buckets.putIfAbsent(market, new HashMap<>()); - buckets.get(market).putIfAbsent(currentMessage.getOwnerNodeAddress(), new Aggregator()); - buckets.get(market).get(currentMessage.getOwnerNodeAddress()).increment(); - } - } - - private class VolumePerTraderStatistics extends OfferStatistics> { - - @Override - void process(String market, OfferPayload currentMessage) { - buckets.putIfAbsent(market, new HashMap<>()); - buckets.get(market).putIfAbsent(currentMessage.getOwnerNodeAddress(), new Aggregator()); - buckets.get(market).get(currentMessage.getOwnerNodeAddress()).add(currentMessage.getAmount()); - } - } - - private class VersionsStatistics extends Statistics { - - @Override - public void log(Object message) { - - if (message instanceof OfferPayload) { - OfferPayload offerPayload = (OfferPayload) message; - String version = "v" + OfferUtil.getVersionFromId(offerPayload.getId()); - buckets.putIfAbsent(version, new Aggregator()); - buckets.get(version).increment(); - } - } - } - - public P2PMarketStats(Reporter graphiteReporter) { - super(graphiteReporter); - } - - @Override - protected List getRequests() { - List result = new ArrayList<>(); - - Random random = new Random(); - result.add(new PreliminaryGetDataRequest(random.nextInt(), hashes)); - - return result; - } - - protected void createHistogram(List input, String market, Map report) { - int numberOfBins = 5; - - // - get biggest offer - double max = input.stream().max(Long::compareTo).map(value -> value * 1.01).orElse(0.0); - - // - create histogram - input.stream().collect( - Collectors.groupingBy(aLong -> aLong == max ? numberOfBins - 1 : (int) Math.floor(aLong / (max / numberOfBins)), Collectors.counting())). - forEach((integer, integer2) -> report.put(market + ".bin_" + integer, String.valueOf(integer2))); - - report.put(market + ".number_of_bins", String.valueOf(numberOfBins)); - report.put(market + ".max", String.valueOf((int) max)); - } - - @Override - protected void report() { - Map report = new HashMap<>(); - bucketsPerHost.values().stream().findFirst().ifPresent(nodeAddressStatisticsEntry -> nodeAddressStatisticsEntry.values().forEach((market, numberOfOffers) -> report.put(market, String.valueOf(((Aggregator) numberOfOffers).value())))); - reporter.report(report, getName() + ".offerCount"); - - // do offerbook volume statistics - report.clear(); - offerVolumeBucketsPerHost.values().stream().findFirst().ifPresent(aggregatorStatistics -> aggregatorStatistics.values().forEach((market, numberOfOffers) -> report.put(market, String.valueOf(numberOfOffers.value())))); - reporter.report(report, getName() + ".volume"); - - // do the offer vs volume histogram - report.clear(); - // - get a data set - offerVolumeDistributionBucketsPerHost.values().stream().findFirst().ifPresent(listStatistics -> listStatistics.values().forEach((market, offers) -> { - createHistogram(offers, market, report); - })); - reporter.report(report, getName() + ".volume-per-offer-distribution"); - - // do offers per trader - report.clear(); - // - get a data set - offersPerTraderBucketsPerHost.values().stream().findFirst().ifPresent(mapStatistics -> mapStatistics.values().forEach((market, stuff) -> { - List offerPerTrader = stuff.values().stream().map(Aggregator::value).collect(Collectors.toList()); - - createHistogram(offerPerTrader, market, report); - })); - reporter.report(report, getName() + ".traders_by_number_of_offers"); - - // do volume per trader - report.clear(); - // - get a data set - volumePerTraderBucketsPerHost.values().stream().findFirst().ifPresent(mapStatistics -> mapStatistics.values().forEach((market, stuff) -> { - List volumePerTrader = stuff.values().stream().map(Aggregator::value).collect(Collectors.toList()); - - createHistogram(volumePerTrader, market, report); - })); - reporter.report(report, getName() + ".traders_by_volume"); - - // do version statistics - report.clear(); - Optional> optionalStatistics = versionBucketsPerHost.values().stream().findAny(); - optionalStatistics.ifPresent(aggregatorStatistics -> aggregatorStatistics.values() - .forEach((version, numberOfOccurrences) -> report.put(version, String.valueOf(numberOfOccurrences.value())))); - reporter.report(report, "versions"); - } - - protected boolean treatMessage(NetworkEnvelope networkEnvelope, Connection connection) { - checkNotNull(connection.getPeersNodeAddressProperty(), - "although the property is nullable, we need it to not be null"); - - if (networkEnvelope instanceof GetDataResponse) { - - Statistics offerCount = new OfferCountStatistics(); - Statistics offerVolume = new OfferVolumeStatistics(); - Statistics offerVolumeDistribution = new OfferVolumeDistributionStatistics(); - Statistics offersPerTrader = new OffersPerTraderStatistics(); - Statistics volumePerTrader = new VolumePerTraderStatistics(); - Statistics versions = new VersionsStatistics(); - - GetDataResponse dataResponse = (GetDataResponse) networkEnvelope; - final Set dataSet = dataResponse.getDataSet(); - dataSet.forEach(e -> { - final ProtectedStoragePayload protectedStoragePayload = e.getProtectedStoragePayload(); - if (protectedStoragePayload == null) { - log.warn("StoragePayload was null: {}", networkEnvelope.toString()); - return; - } - - offerCount.log(protectedStoragePayload); - offerVolume.log(protectedStoragePayload); - offerVolumeDistribution.log(protectedStoragePayload); - offersPerTrader.log(protectedStoragePayload); - volumePerTrader.log(protectedStoragePayload); - versions.log(protectedStoragePayload); - }); - - dataResponse.getPersistableNetworkPayloadSet().forEach(persistableNetworkPayload -> { - // memorize message hashes - //Byte[] bytes = new Byte[persistableNetworkPayload.getHash().length]; - //Arrays.setAll(bytes, n -> persistableNetworkPayload.getHash()[n]); - - //hashes.add(bytes); - - hashes.add(persistableNetworkPayload.getHash()); - }); - - bucketsPerHost.put(connection.getPeersNodeAddressProperty().getValue(), offerCount); - offerVolumeBucketsPerHost.put(connection.getPeersNodeAddressProperty().getValue(), offerVolume); - offerVolumeDistributionBucketsPerHost.put(connection.getPeersNodeAddressProperty().getValue(), offerVolumeDistribution); - offersPerTraderBucketsPerHost.put(connection.getPeersNodeAddressProperty().getValue(), offersPerTrader); - volumePerTraderBucketsPerHost.put(connection.getPeersNodeAddressProperty().getValue(), volumePerTrader); - versionBucketsPerHost.put(connection.getPeersNodeAddressProperty().getValue(), versions); - return true; - } - return false; - } -} diff --git a/monitor/src/main/java/bisq/monitor/metric/P2PNetworkLoad.java b/monitor/src/main/java/bisq/monitor/metric/P2PNetworkLoad.java deleted file mode 100644 index ff4bb78b6f1..00000000000 --- a/monitor/src/main/java/bisq/monitor/metric/P2PNetworkLoad.java +++ /dev/null @@ -1,245 +0,0 @@ -/* - * This file is part of Bisq. - * - * Bisq is free software: you can redistribute it and/or modify it - * under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or (at - * your option) any later version. - * - * Bisq is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public - * License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with Bisq. If not, see . - */ - -package bisq.monitor.metric; - -import bisq.monitor.AvailableTor; -import bisq.monitor.Metric; -import bisq.monitor.Monitor; -import bisq.monitor.Reporter; -import bisq.monitor.ThreadGate; - -import bisq.core.network.p2p.seed.DefaultSeedNodeRepository; -import bisq.core.proto.network.CoreNetworkProtoResolver; -import bisq.core.proto.persistable.CorePersistenceProtoResolver; - -import bisq.network.p2p.network.Connection; -import bisq.network.p2p.network.MessageListener; -import bisq.network.p2p.network.NetworkNode; -import bisq.network.p2p.network.SetupListener; -import bisq.network.p2p.network.TorNetworkNode; -import bisq.network.p2p.peers.PeerManager; -import bisq.network.p2p.peers.keepalive.KeepAliveManager; -import bisq.network.p2p.peers.peerexchange.PeerExchangeManager; -import bisq.network.p2p.storage.messages.BroadcastMessage; - -import bisq.common.ClockWatcher; -import bisq.common.config.Config; -import bisq.common.file.CorruptedStorageFileHandler; -import bisq.common.persistence.PersistenceManager; -import bisq.common.proto.network.NetworkEnvelope; -import bisq.common.proto.network.NetworkProtoResolver; - -import java.time.Clock; - -import java.io.File; - -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedHashMap; -import java.util.Map; -import java.util.Properties; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; - -import lombok.extern.slf4j.Slf4j; - -/** - * Contacts a list of hosts and asks them for all the data we do not have. The - * answers are then compiled into buckets of message types. Based on these - * buckets, the Metric reports (for each host) the message types observed and - * their number along with a relative comparison between all hosts. - * - * @author Florian Reimair - * - */ -@Slf4j -public class P2PNetworkLoad extends Metric implements MessageListener, SetupListener { - - private static final String TOR_PROXY_PORT = "run.torProxyPort"; - private static final String MAX_CONNECTIONS = "run.maxConnections"; - private static final String HISTORY_SIZE = "run.historySize"; - private NetworkNode networkNode; - private final File torHiddenServiceDir = new File("metric_" + getName()); - private final ThreadGate hsReady = new ThreadGate(); - private final Map buckets = new ConcurrentHashMap<>(); - - /** - * Buffers the last X message we received. New messages will only be logged in case - * the message isn't already in the history. Note that the oldest message hashes are - * dropped to record newer hashes. - */ - private Map history; - private long lastRun = 0; - - /** - * History implementation using a {@link LinkedHashMap} and its - * {@link LinkedHashMap#removeEldestEntry(Map.Entry)} option. - */ - private static class FixedSizeHistoryTracker extends LinkedHashMap { - final int historySize; - - FixedSizeHistoryTracker(int historySize) { - super(historySize, 10, true); - this.historySize = historySize; - } - - @Override - protected boolean removeEldestEntry(Map.Entry eldest) { - return size() > historySize; - } - } - - @Override - protected void execute() { - - // in case we do not have a NetworkNode up and running, we create one - if (null == networkNode) { - // prepare the gate - hsReady.engage(); - - // start the network node - networkNode = new TorNetworkNode(Integer.parseInt(configuration.getProperty(TOR_PROXY_PORT, "9053")), - new CoreNetworkProtoResolver(Clock.systemDefaultZone()), false, - new AvailableTor(Monitor.TOR_WORKING_DIR, torHiddenServiceDir.getName()), null); - networkNode.start(this); - - // wait for the HS to be published - hsReady.await(); - - // boot up P2P node - try { - Config config = new Config(); - CorruptedStorageFileHandler corruptedStorageFileHandler = new CorruptedStorageFileHandler(); - int maxConnections = Integer.parseInt(configuration.getProperty(MAX_CONNECTIONS, "12")); - NetworkProtoResolver networkProtoResolver = new CoreNetworkProtoResolver(Clock.systemDefaultZone()); - CorePersistenceProtoResolver persistenceProtoResolver = new CorePersistenceProtoResolver(null, - networkProtoResolver); - DefaultSeedNodeRepository seedNodeRepository = new DefaultSeedNodeRepository(config); - PeerManager peerManager = new PeerManager(networkNode, seedNodeRepository, new ClockWatcher(), - new PersistenceManager<>(torHiddenServiceDir, persistenceProtoResolver, corruptedStorageFileHandler), maxConnections); - - // init file storage - peerManager.readPersisted(() -> { - }); - - PeerExchangeManager peerExchangeManager = new PeerExchangeManager(networkNode, seedNodeRepository, - peerManager); - // updates the peer list every now and then as well - peerExchangeManager - .requestReportedPeersFromSeedNodes(seedNodeRepository.getSeedNodeAddresses().iterator().next()); - - KeepAliveManager keepAliveManager = new KeepAliveManager(networkNode, peerManager); - keepAliveManager.start(); - - networkNode.addMessageListener(this); - } catch (Throwable e) { - e.printStackTrace(); - } - } - - // report - Map report = new HashMap<>(); - - if (lastRun != 0 && System.currentTimeMillis() - lastRun != 0) { - // - normalize to data/minute - double perMinuteFactor = 60000.0 / (System.currentTimeMillis() - lastRun); - - - // - get snapshot so we do not loose data - Set keys = new HashSet<>(buckets.keySet()); - - // - transfer values to report - keys.forEach(key -> { - int value = buckets.get(key).getAndReset(); - if (value != 0) { - report.put(key, String.format("%.2f", value * perMinuteFactor)); - } - }); - - // - report - reporter.report(report, getName()); - } - - // - reset last run - lastRun = System.currentTimeMillis(); - } - - public P2PNetworkLoad(Reporter reporter) { - super(reporter); - } - - @Override - public void configure(Properties properties) { - super.configure(properties); - - history = Collections.synchronizedMap(new FixedSizeHistoryTracker<>(Integer.parseInt(configuration.getProperty(HISTORY_SIZE, "200")))); - } - - /** - * Efficient way to count message occurrences. - */ - private static class Counter { - private int value = 1; - - synchronized int getAndReset() { - try { - return value; - } finally { - value = 0; - } - } - - synchronized void increment() { - value++; - } - } - - @Override - public void onMessage(NetworkEnvelope networkEnvelope, Connection connection) { - if (networkEnvelope instanceof BroadcastMessage) { - try { - if (history.get(networkEnvelope.hashCode()) == null) { - history.put(networkEnvelope.hashCode(), null); - buckets.get(networkEnvelope.getClass().getSimpleName()).increment(); - } - } catch (NullPointerException e) { - // use exception handling because we hardly ever need to add a fresh bucket - buckets.put(networkEnvelope.getClass().getSimpleName(), new Counter()); - } - } - } - - @Override - public void onTorNodeReady() { - } - - @Override - public void onHiddenServicePublished() { - // open the gate - hsReady.proceed(); - } - - @Override - public void onSetupFailed(Throwable throwable) { - } - - @Override - public void onRequestCustomBridges() { - } -} diff --git a/monitor/src/main/java/bisq/monitor/metric/P2PRoundTripTime.java b/monitor/src/main/java/bisq/monitor/metric/P2PRoundTripTime.java deleted file mode 100644 index bef8ad22f5c..00000000000 --- a/monitor/src/main/java/bisq/monitor/metric/P2PRoundTripTime.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * This file is part of Bisq. - * - * bisq is free software: you can redistribute it and/or modify it - * under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or (at - * your option) any later version. - * - * bisq is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public - * License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with bisq. If not, see . - */ - -package bisq.monitor.metric; - -import bisq.monitor.OnionParser; -import bisq.monitor.Reporter; -import bisq.monitor.StatisticsHelper; - -import bisq.network.p2p.NodeAddress; -import bisq.network.p2p.network.CloseConnectionReason; -import bisq.network.p2p.network.Connection; -import bisq.network.p2p.peers.keepalive.messages.Ping; -import bisq.network.p2p.peers.keepalive.messages.Pong; - -import bisq.common.proto.network.NetworkEnvelope; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Random; - -import static com.google.common.base.Preconditions.checkNotNull; - -public class P2PRoundTripTime extends P2PSeedNodeSnapshotBase { - - private static final String SAMPLE_SIZE = "run.sampleSize"; - private final Map sentAt = new HashMap<>(); - private Map measurements = new HashMap<>(); - - public P2PRoundTripTime(Reporter reporter) { - super(reporter); - } - - /** - * Use a counter to do statistics. - */ - private class Statistics { - - private final List samples = new ArrayList<>(); - - public synchronized void log(Object message) { - Pong pong = (Pong) message; - Long start = sentAt.get(pong.getRequestNonce()); - if (start != null) - samples.add(System.currentTimeMillis() - start); - } - - public List values() { - return samples; - } - } - - @Override - protected List getRequests() { - List result = new ArrayList<>(); - - Random random = new Random(); - for (int i = 0; i < Integer.parseInt(configuration.getProperty(SAMPLE_SIZE, "1")); i++) - result.add(new Ping(random.nextInt(), 42)); - - return result; - } - - @Override - protected void aboutToSend(NetworkEnvelope message) { - sentAt.put(((Ping) message).getNonce(), System.currentTimeMillis()); - } - - @Override - protected boolean treatMessage(NetworkEnvelope networkEnvelope, Connection connection) { - if (networkEnvelope instanceof Pong) { - checkNotNull(connection.getPeersNodeAddressProperty(), - "although the property is nullable, we need it to not be null"); - - measurements.putIfAbsent(connection.getPeersNodeAddressProperty().getValue(), new Statistics()); - - measurements.get(connection.getPeersNodeAddressProperty().getValue()).log(networkEnvelope); - - connection.shutDown(CloseConnectionReason.APP_SHUT_DOWN); - return true; - } - return false; - } - - @Override - void report() { - // report - measurements.forEach(((nodeAddress, samples) -> - reporter.report(StatisticsHelper.process(samples.values()), - getName() + "." + OnionParser.prettyPrint(nodeAddress)) - )); - // clean up for next round - measurements = new HashMap<>(); - } -} diff --git a/monitor/src/main/java/bisq/monitor/metric/P2PSeedNodeSnapshot.java b/monitor/src/main/java/bisq/monitor/metric/P2PSeedNodeSnapshot.java deleted file mode 100644 index 3072abea393..00000000000 --- a/monitor/src/main/java/bisq/monitor/metric/P2PSeedNodeSnapshot.java +++ /dev/null @@ -1,292 +0,0 @@ -/* - * This file is part of Bisq. - * - * bisq is free software: you can redistribute it and/or modify it - * under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or (at - * your option) any later version. - * - * bisq is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public - * License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with bisq. If not, see . - */ - -package bisq.monitor.metric; - -import bisq.monitor.OnionParser; -import bisq.monitor.Reporter; - -import bisq.core.dao.monitoring.model.StateHash; -import bisq.core.dao.monitoring.network.messages.GetBlindVoteStateHashesRequest; -import bisq.core.dao.monitoring.network.messages.GetDaoStateHashesRequest; -import bisq.core.dao.monitoring.network.messages.GetProposalStateHashesRequest; -import bisq.core.dao.monitoring.network.messages.GetStateHashesResponse; - -import bisq.network.p2p.NodeAddress; -import bisq.network.p2p.network.Connection; -import bisq.network.p2p.peers.getdata.messages.GetDataResponse; -import bisq.network.p2p.peers.getdata.messages.PreliminaryGetDataRequest; -import bisq.network.p2p.storage.payload.ProtectedStorageEntry; -import bisq.network.p2p.storage.payload.ProtectedStoragePayload; - -import bisq.common.proto.network.NetworkEnvelope; - -import java.net.MalformedURLException; - -import java.nio.ByteBuffer; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Comparator; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Random; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; - -import lombok.Getter; -import lombok.extern.slf4j.Slf4j; - -import static com.google.common.base.Preconditions.checkNotNull; - -/** - * Contacts a list of hosts and asks them for all the data excluding persisted messages. The - * answers are then compiled into buckets of message types. Based on these - * buckets, the Metric reports (for each host) the message types observed and - * their number. - * - * Furthermore, since the DAO is a thing now, the consistency of the DAO state held by each host is assessed and reported. - * - * @author Florian Reimair - * - */ -@Slf4j -public class P2PSeedNodeSnapshot extends P2PSeedNodeSnapshotBase { - - final Map>> bucketsPerHost = new ConcurrentHashMap<>(); - private int daostateheight = 594000; - private int proposalheight = daostateheight; - private int blindvoteheight = daostateheight; - - /** - * Use a counter to do statistics. - */ - private static class MyStatistics extends Statistics> { - - @Override - public synchronized void log(Object message) { - - // For logging different data types - String className = message.getClass().getSimpleName(); - - buckets.putIfAbsent(className, new HashSet<>()); - buckets.get(className).add(message.hashCode()); - } - } - - public P2PSeedNodeSnapshot(Reporter reporter) { - super(reporter); - } - - protected List getRequests() { - List result = new ArrayList<>(); - - Random random = new Random(); - result.add(new PreliminaryGetDataRequest(random.nextInt(), hashes)); - - result.add(new GetDaoStateHashesRequest(daostateheight, random.nextInt())); - - result.add(new GetProposalStateHashesRequest(proposalheight, random.nextInt())); - - result.add(new GetBlindVoteStateHashesRequest(blindvoteheight, random.nextInt())); - - return result; - } - - /** - * Report all the stuff. Uses the configured reporter directly. - */ - void report() { - - // report - Map report = new HashMap<>(); - // - assemble histograms - bucketsPerHost.forEach((host, statistics) -> statistics.values().forEach((type, set) -> report - .put(OnionParser.prettyPrint(host) + ".numberOfMessages." + type, Integer.toString(set.size())))); - - // - assemble diffs - // - transfer values - Map>> messagesPerHost = new HashMap<>(); - bucketsPerHost.forEach((host, value) -> messagesPerHost.put(OnionParser.prettyPrint(host), value)); - - // - pick reference seed node and its values - String referenceHost = "overall_number_of_unique_messages"; - Map> referenceValues = new HashMap<>(); - messagesPerHost.forEach((host, statistics) -> statistics.values().forEach((type, set) -> { - referenceValues.putIfAbsent(type, new HashSet<>()); - referenceValues.get(type).addAll(set); - })); - - // - calculate diffs - messagesPerHost.forEach( - (host, statistics) -> { - statistics.values().forEach((messageType, set) -> { - try { - report.put(OnionParser.prettyPrint(host) + ".relativeNumberOfMessages." + messageType, - String.valueOf(set.size() - referenceValues.get(messageType).size())); - } catch (MalformedURLException | NullPointerException e) { - log.error("we should never have gotten here", e); - } - }); - try { - report.put(OnionParser.prettyPrint(host) + ".referenceHost", referenceHost); - } catch (MalformedURLException ignore) { - log.error("we should never got here"); - } - }); - - // cleanup for next run - bucketsPerHost.forEach((host, statistics) -> statistics.reset()); - - // when our hash cache exceeds a hard limit, we clear the cache and start anew - if (hashes.size() > 150000) - hashes.clear(); - - // - report - reporter.report(report, getName()); - - // - assemble dao report - Map daoreport = new HashMap<>(); - - // - transcode - Map> perType = new HashMap<>(); - daoData.forEach((nodeAddress, daostatistics) -> daostatistics.values().forEach((type, tuple) -> { - perType.putIfAbsent(type, new HashMap<>()); - perType.get(type).put(nodeAddress, tuple); - })); - - // - process dao data - perType.forEach((type, nodeAddressTupleMap) -> { - // - find head - int head = nodeAddressTupleMap.values().stream().max(Comparator.comparingLong(Tuple::getHeight)) - .map(value -> (int) value.height) - .orElse(0); - int oldest = nodeAddressTupleMap.values().stream().min(Comparator.comparingLong(Tuple::getHeight)) - .map(value -> (int) value.height) - .orElse(0); - - // - update queried height - if (type.contains("DaoState")) - daostateheight = oldest - 20; - else if (type.contains("Proposal")) - proposalheight = oldest - 20; - else - blindvoteheight = oldest - 20; - - // - calculate diffs - nodeAddressTupleMap.forEach((nodeAddress, tuple) -> daoreport.put(type + "." + OnionParser.prettyPrint(nodeAddress) + ".head", Long.toString(tuple.height - head))); - - // - memorize hashes - Map hitcount = new HashMap<>(); - nodeAddressTupleMap.forEach((nodeAddress, tuple) -> { - ByteBuffer hash = ByteBuffer.wrap(tuple.hash); - if (hitcount.containsKey(hash)) { - hitcount.put(hash, hitcount.get(hash) + 1); - } else - hitcount.put(hash, 1); - }); - - hitcount.clear(); - - nodeAddressTupleMap.forEach((nodeAddress, tuple) -> - daoreport.put(type + "." + OnionParser.prettyPrint(nodeAddress) + ".hash", - Integer.toString(Arrays.asList(hitcount.entrySet().stream() - .sorted((o1, o2) -> o2.getValue().compareTo(o1.getValue())) - .map(Map.Entry::getKey).toArray()).indexOf(ByteBuffer - .wrap(tuple.hash))))); - - // - report reference head - daoreport.put(type + ".referenceHead", Integer.toString(head)); - }); - - daoData.clear(); - - // - report - reporter.report(daoreport, "DaoStateSnapshot"); - } - - private static class Tuple { - @Getter - private final long height; - private final byte[] hash; - - Tuple(long height, byte[] hash) { - this.height = height; - this.hash = hash; - } - } - - private class DaoStatistics extends Statistics { - - @Override - public void log(Object message) { - // get last entry - StateHash last = (StateHash) ((GetStateHashesResponse) message).getStateHashes().get(((GetStateHashesResponse) message).getStateHashes().size() - 1); - - // For logging different data types - String className = last.getClass().getSimpleName(); - - buckets.putIfAbsent(className, new Tuple(last.getHeight(), last.getHash())); - } - } - - private final Map> daoData = new ConcurrentHashMap<>(); - - protected boolean treatMessage(NetworkEnvelope networkEnvelope, Connection connection) { - checkNotNull(connection.getPeersNodeAddressProperty(), - "although the property is nullable, we need it to not be null"); - - if (networkEnvelope instanceof GetDataResponse) { - - Statistics result = new MyStatistics(); - - GetDataResponse dataResponse = (GetDataResponse) networkEnvelope; - final Set dataSet = dataResponse.getDataSet(); - dataSet.forEach(e -> { - final ProtectedStoragePayload protectedStoragePayload = e.getProtectedStoragePayload(); - if (protectedStoragePayload == null) { - log.warn("StoragePayload was null: {}", networkEnvelope.toString()); - return; - } - - result.log(protectedStoragePayload); - }); - - dataResponse.getPersistableNetworkPayloadSet().forEach(persistableNetworkPayload -> { - // memorize message hashes - //Byte[] bytes = new Byte[persistableNetworkPayload.getHash().length]; - //Arrays.setAll(bytes, n -> persistableNetworkPayload.getHash()[n]); - - //hashes.add(bytes); - - hashes.add(persistableNetworkPayload.getHash()); - }); - - bucketsPerHost.put(connection.getPeersNodeAddressProperty().getValue(), result); - return true; - } else if (networkEnvelope instanceof GetStateHashesResponse) { - daoData.putIfAbsent(connection.getPeersNodeAddressProperty().getValue(), new DaoStatistics()); - - daoData.get(connection.getPeersNodeAddressProperty().getValue()).log(networkEnvelope); - - return true; - } - return false; - } -} diff --git a/monitor/src/main/java/bisq/monitor/metric/P2PSeedNodeSnapshotBase.java b/monitor/src/main/java/bisq/monitor/metric/P2PSeedNodeSnapshotBase.java deleted file mode 100644 index 9550b3dae9f..00000000000 --- a/monitor/src/main/java/bisq/monitor/metric/P2PSeedNodeSnapshotBase.java +++ /dev/null @@ -1,241 +0,0 @@ -/* - * This file is part of Bisq. - * - * bisq is free software: you can redistribute it and/or modify it - * under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or (at - * your option) any later version. - * - * bisq is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public - * License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with bisq. If not, see . - */ - -package bisq.monitor.metric; - -import bisq.monitor.AvailableTor; -import bisq.monitor.Metric; -import bisq.monitor.Monitor; -import bisq.monitor.OnionParser; -import bisq.monitor.Reporter; -import bisq.monitor.ThreadGate; - -import bisq.core.account.witness.AccountAgeWitnessStore; -import bisq.core.proto.network.CoreNetworkProtoResolver; -import bisq.core.proto.persistable.CorePersistenceProtoResolver; -import bisq.core.trade.statistics.TradeStatistics3Store; - -import bisq.network.p2p.CloseConnectionMessage; -import bisq.network.p2p.NodeAddress; -import bisq.network.p2p.network.Connection; -import bisq.network.p2p.network.MessageListener; -import bisq.network.p2p.network.NetworkNode; -import bisq.network.p2p.network.TorNetworkNode; - -import bisq.common.app.Version; -import bisq.common.config.BaseCurrencyNetwork; -import bisq.common.persistence.PersistenceManager; -import bisq.common.proto.network.NetworkEnvelope; - -import com.google.common.util.concurrent.FutureCallback; -import com.google.common.util.concurrent.Futures; -import com.google.common.util.concurrent.MoreExecutors; -import com.google.common.util.concurrent.SettableFuture; - -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; -import java.util.Properties; -import java.util.Set; -import java.util.TreeSet; -import java.util.concurrent.ConcurrentHashMap; -import java.util.stream.Collectors; - -import lombok.extern.slf4j.Slf4j; - -import org.jetbrains.annotations.NotNull; - -/** - * Contacts a list of hosts and asks them for all the data excluding persisted messages. The - * answers are then compiled into buckets of message types. Based on these - * buckets, the Metric reports (for each host) the message types observed and - * their number. - * - * @author Florian Reimair - * - */ -@Slf4j -public abstract class P2PSeedNodeSnapshotBase extends Metric implements MessageListener { - - private static final String HOSTS = "run.hosts"; - private static final String TOR_PROXY_PORT = "run.torProxyPort"; - private static final String DATABASE_DIR = "run.dbDir"; - final Map> bucketsPerHost = new ConcurrentHashMap<>(); - private final ThreadGate gate = new ThreadGate(); - protected final Set hashes = new TreeSet<>(Arrays::compare); - - /** - * Statistics Interface for use with derived classes. - * - * @param the value type of the statistics implementation - */ - protected abstract static class Statistics { - protected final Map buckets = new HashMap<>(); - - abstract void log(Object message); - - Map values() { - return buckets; - } - - void reset() { - buckets.clear(); - } - } - - public P2PSeedNodeSnapshotBase(Reporter reporter) { - super(reporter); - } - - @Override - public void configure(Properties properties) { - super.configure(properties); - - if (hashes.isEmpty() && configuration.getProperty(DATABASE_DIR) != null) { - File dir = new File(configuration.getProperty(DATABASE_DIR)); - String networkPostfix = "_" + BaseCurrencyNetwork.values()[Version.getBaseCurrencyNetwork()].toString(); - try { - CorePersistenceProtoResolver persistenceProtoResolver = new CorePersistenceProtoResolver(null, null); - - //TODO will not work with historical data... should be refactored to re-use code for reading resource files - TradeStatistics3Store tradeStatistics3Store = new TradeStatistics3Store(); - PersistenceManager tradeStatistics3PersistenceManager = new PersistenceManager<>(dir, - persistenceProtoResolver, null); - tradeStatistics3PersistenceManager.initialize(tradeStatistics3Store, - tradeStatistics3Store.getDefaultStorageFileName() + networkPostfix, - PersistenceManager.Source.NETWORK); - TradeStatistics3Store persistedTradeStatistics3Store = tradeStatistics3PersistenceManager.getPersisted(); - if (persistedTradeStatistics3Store != null) { - tradeStatistics3Store.getMap().putAll(persistedTradeStatistics3Store.getMap()); - } - hashes.addAll(tradeStatistics3Store.getMap().keySet().stream() - .map(byteArray -> byteArray.bytes).collect(Collectors.toSet())); - - AccountAgeWitnessStore accountAgeWitnessStore = new AccountAgeWitnessStore(); - PersistenceManager accountAgeWitnessPersistenceManager = new PersistenceManager<>(dir, - persistenceProtoResolver, null); - accountAgeWitnessPersistenceManager.initialize(accountAgeWitnessStore, - accountAgeWitnessStore.getDefaultStorageFileName() + networkPostfix, - PersistenceManager.Source.NETWORK); - AccountAgeWitnessStore persistedAccountAgeWitnessStore = accountAgeWitnessPersistenceManager.getPersisted(); - if (persistedAccountAgeWitnessStore != null) { - accountAgeWitnessStore.getMap().putAll(persistedAccountAgeWitnessStore.getMap()); - } - hashes.addAll(accountAgeWitnessStore.getMap().keySet().stream() - .map(byteArray -> byteArray.bytes).collect(Collectors.toSet())); - } catch (NullPointerException e) { - // in case there is no store file - log.error("There is no storage file where there should be one: {}", dir.getAbsolutePath()); - } - } - } - - @Override - protected void execute() { - // start the network node - final NetworkNode networkNode = new TorNetworkNode(Integer.parseInt(configuration.getProperty(TOR_PROXY_PORT, "9054")), - new CoreNetworkProtoResolver(Clock.systemDefaultZone()), false, - new AvailableTor(Monitor.TOR_WORKING_DIR, "unused"), null); - // we do not need to start the networkNode, as we do not need the HS - //networkNode.start(this); - - // clear our buckets - bucketsPerHost.clear(); - - getRequests().forEach(getDataRequest -> send(networkNode, getDataRequest)); - - report(); - } - - protected abstract List getRequests(); - - protected void send(NetworkNode networkNode, NetworkEnvelope message) { - - ArrayList threadList = new ArrayList<>(); - - // for each configured host - for (String current : configuration.getProperty(HOSTS, "").split(",")) { - threadList.add(new Thread(() -> { - - try { - // parse Url - NodeAddress target = OnionParser.getNodeAddress(current); - - // do the data request - aboutToSend(message); - SettableFuture future = networkNode.sendMessage(target, message); - - Futures.addCallback(future, new FutureCallback<>() { - @Override - public void onSuccess(Connection connection) { - connection.addMessageListener(P2PSeedNodeSnapshotBase.this); - } - - @Override - public void onFailure(@NotNull Throwable throwable) { - gate.proceed(); - log.error( - "Sending {} failed. That is expected if the peer is offline.\n\tException={}", message.getClass().getSimpleName(), throwable.getMessage()); - } - }, MoreExecutors.directExecutor()); - - } catch (Exception e) { - gate.proceed(); // release the gate on error - e.printStackTrace(); - } - }, current)); - } - - gate.engage(threadList.size()); - - // start all threads and wait until they all finished. We do that so we can - // minimize the time between querying the hosts and therefore the chance of - // inconsistencies. - threadList.forEach(Thread::start); - - gate.await(); - } - - protected void aboutToSend(NetworkEnvelope message) { - } - - /** - * Report all the stuff. Uses the configured reporter directly. - */ - abstract void report(); - - @Override - public void onMessage(NetworkEnvelope networkEnvelope, Connection connection) { - if (treatMessage(networkEnvelope, connection)) { - gate.proceed(); - } else if (networkEnvelope instanceof CloseConnectionMessage) { - gate.unlock(); - } else { - log.warn("Got an unexpected message of type <{}>", - networkEnvelope.getClass().getSimpleName()); - } - connection.removeMessageListener(this); - } - - protected abstract boolean treatMessage(NetworkEnvelope networkEnvelope, Connection connection); -} diff --git a/monitor/src/main/java/bisq/monitor/metric/PriceNodeStats.java b/monitor/src/main/java/bisq/monitor/metric/PriceNodeStats.java deleted file mode 100644 index fd10691f727..00000000000 --- a/monitor/src/main/java/bisq/monitor/metric/PriceNodeStats.java +++ /dev/null @@ -1,165 +0,0 @@ -/* - * This file is part of Bisq. - * - * bisq is free software: you can redistribute it and/or modify it - * under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or (at - * your option) any later version. - * - * bisq is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public - * License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with bisq. If not, see . - */ - -package bisq.monitor.metric; - -import bisq.monitor.Metric; -import bisq.monitor.OnionParser; -import bisq.monitor.Reporter; - -import bisq.asset.Asset; -import bisq.asset.AssetRegistry; - -import bisq.network.p2p.NodeAddress; - -import org.berndpruenster.netlayer.tor.Tor; -import org.berndpruenster.netlayer.tor.TorCtlException; - -import com.runjva.sourceforge.jsocks.protocol.Socks5Proxy; -import com.runjva.sourceforge.jsocks.protocol.SocksSocket; - -import java.io.BufferedReader; -import java.io.BufferedWriter; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.OutputStreamWriter; -import java.io.PrintWriter; - -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import lombok.extern.slf4j.Slf4j; - -import static com.google.common.base.Preconditions.checkNotNull; - -/** - * Fetches fee and price data from the configured price nodes. - * Based on the work of HarryMcFinned. - * - * @author Florian Reimair - * @author HarryMcFinned - * - */ -@Slf4j -public class PriceNodeStats extends Metric { - - private static final String HOSTS = "run.hosts"; - private static final String IGNORE = "dashTxFee ltcTxFee dogeTxFee"; - // poor mans JSON parser - private final Pattern stringNumberPattern = Pattern.compile("\"(.+)\" ?: ?(\\d+)"); - private final Pattern pricePattern = Pattern.compile("\"price\" ?: ?([\\d.]+)"); - private final Pattern currencyCodePattern = Pattern.compile("\"currencyCode\" ?: ?\"([A-Z]+)\""); - private final List assets = Arrays.asList(new AssetRegistry().stream().map(Asset::getTickerSymbol).toArray()); - - public PriceNodeStats(Reporter reporter) { - super(reporter); - } - - @Override - protected void execute() { - try { - // fetch proxy - Tor tor = Tor.getDefault(); - checkNotNull(tor, "tor must not be null"); - Socks5Proxy proxy = tor.getProxy(); - - String[] hosts = configuration.getProperty(HOSTS, "").split(","); - - Collections.shuffle(Arrays.asList(hosts)); - - // for each configured host - for (String current : hosts) { - Map result = new HashMap<>(); - // parse Url - NodeAddress tmp = OnionParser.getNodeAddress(current); - - // connect - try { - SocksSocket socket = new SocksSocket(proxy, tmp.getHostName(), tmp.getPort()); - - // prepare to receive data - BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream())); - - // ask for fee data - PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()))); - out.println("GET /getFees/"); - out.println(); - out.flush(); - - // sift through the received lines and see if we got something json-like - String line; - while ((line = in.readLine()) != null) { - Matcher matcher = stringNumberPattern.matcher(line); - if (matcher.find()) - if (!IGNORE.contains(matcher.group(1))) - result.put("fees." + matcher.group(1), matcher.group(2)); - } - - in.close(); - out.close(); - socket.close(); - - // connect - socket = new SocksSocket(proxy, tmp.getHostName(), tmp.getPort()); - - // prepare to receive data - in = new BufferedReader(new InputStreamReader(socket.getInputStream())); - - // ask for exchange rate data - out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()))); - out.println("GET /getAllMarketPrices/"); - out.println(); - out.flush(); - - String currencyCode = ""; - while ((line = in.readLine()) != null) { - Matcher currencyCodeMatcher = currencyCodePattern.matcher(line); - Matcher priceMatcher = pricePattern.matcher(line); - if (currencyCodeMatcher.find()) { - currencyCode = currencyCodeMatcher.group(1); - if (!assets.contains(currencyCode)) - currencyCode = ""; - } else if (!"".equals(currencyCode) && priceMatcher.find()) - result.put("price." + currencyCode, priceMatcher.group(1)); - } - - // close all the things - in.close(); - out.close(); - socket.close(); - - // report - reporter.report(result, getName()); - - // only ask for data as long as we got none - if (!result.isEmpty()) - break; - } catch (IOException e) { - log.error("{} seems to be down. Trying next configured price node.", tmp.getHostName()); - e.printStackTrace(); - } - } - } catch (TorCtlException | IOException e) { - e.printStackTrace(); - } - } -} diff --git a/monitor/src/main/java/bisq/monitor/metric/TorHiddenServiceStartupTime.java b/monitor/src/main/java/bisq/monitor/metric/TorHiddenServiceStartupTime.java deleted file mode 100644 index 21be8526eff..00000000000 --- a/monitor/src/main/java/bisq/monitor/metric/TorHiddenServiceStartupTime.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * This file is part of Bisq. - * - * Bisq is free software: you can redistribute it and/or modify it - * under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or (at - * your option) any later version. - * - * Bisq is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public - * License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with Bisq. If not, see . - */ - -package bisq.monitor.metric; - -import bisq.monitor.Metric; -import bisq.monitor.Monitor; -import bisq.monitor.Reporter; -import bisq.monitor.ThreadGate; - -import org.berndpruenster.netlayer.tor.HiddenServiceSocket; - -import java.io.File; - -import lombok.extern.slf4j.Slf4j; - -/** - * A Metric to measure the startup time of a Tor Hidden Service on a already - * running Tor. - * - * @author Florian Reimair - */ -@Slf4j -public class TorHiddenServiceStartupTime extends Metric { - - private static final String SERVICE_PORT = "run.servicePort"; - private static final String LOCAL_PORT = "run.localPort"; - private final String hiddenServiceDirectory = "metric_" + getName(); - private final ThreadGate gate = new ThreadGate(); - - public TorHiddenServiceStartupTime(Reporter reporter) { - super(reporter); - } - - @Override - protected void execute() { - // prepare settings. Fetch them every time we run the Metric so we do not have to - // restart on a config update - int localPort = Integer.parseInt(configuration.getProperty(LOCAL_PORT, "9998")); - int servicePort = Integer.parseInt(configuration.getProperty(SERVICE_PORT, "9999")); - - // clear directory so we get a new onion address every time - new File(Monitor.TOR_WORKING_DIR + "/" + hiddenServiceDirectory).delete(); - - log.debug("creating the hidden service"); - - gate.engage(); - - // start timer - we do not need System.nanoTime as we expect our result to be in - // the range of tenth of seconds. - long start = System.currentTimeMillis(); - - HiddenServiceSocket hiddenServiceSocket = new HiddenServiceSocket(localPort, hiddenServiceDirectory, - servicePort); - hiddenServiceSocket.addReadyListener(socket -> { - // stop the timer and report - reporter.report(System.currentTimeMillis() - start, getName()); - log.debug("the hidden service is ready"); - gate.proceed(); - return null; - }); - - gate.await(); - log.debug("going to revoke the hidden service..."); - hiddenServiceSocket.close(); - log.debug("[going to revoke the hidden service...] done"); - } -} diff --git a/monitor/src/main/java/bisq/monitor/metric/TorRoundTripTime.java b/monitor/src/main/java/bisq/monitor/metric/TorRoundTripTime.java deleted file mode 100644 index a40c0261662..00000000000 --- a/monitor/src/main/java/bisq/monitor/metric/TorRoundTripTime.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * This file is part of Bisq. - * - * Bisq is free software: you can redistribute it and/or modify it - * under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or (at - * your option) any later version. - * - * Bisq is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public - * License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with Bisq. If not, see . - */ - -package bisq.monitor.metric; - -import bisq.monitor.Metric; -import bisq.monitor.OnionParser; -import bisq.monitor.Reporter; -import bisq.monitor.StatisticsHelper; - -import bisq.network.p2p.NodeAddress; - -import org.berndpruenster.netlayer.tor.Tor; -import org.berndpruenster.netlayer.tor.TorCtlException; - -import com.runjva.sourceforge.jsocks.protocol.Socks5Proxy; -import com.runjva.sourceforge.jsocks.protocol.SocksSocket; - -import java.io.IOException; - -import java.util.ArrayList; -import java.util.List; - -import static com.google.common.base.Preconditions.checkNotNull; - -/** - * A Metric to measure the round-trip time to the Bisq seed nodes via plain tor. - * - * @author Florian Reimair - */ -public class TorRoundTripTime extends Metric { - - private static final String SAMPLE_SIZE = "run.sampleSize"; - private static final String HOSTS = "run.hosts"; - - public TorRoundTripTime(Reporter reporter) { - super(reporter); - } - - @Override - protected void execute() { - SocksSocket socket; - try { - // fetch proxy - Tor tor = Tor.getDefault(); - checkNotNull(tor, "tor must not be null"); - Socks5Proxy proxy = tor.getProxy(); - - // for each configured host - for (String current : configuration.getProperty(HOSTS, "").split(",")) { - // parse Url - NodeAddress tmp = OnionParser.getNodeAddress(current); - - List samples = new ArrayList<>(); - - while (samples.size() < Integer.parseInt(configuration.getProperty(SAMPLE_SIZE, "1"))) { - // start timer - we do not need System.nanoTime as we expect our result to be in - // seconds time. - long start = System.currentTimeMillis(); - - // connect - socket = new SocksSocket(proxy, tmp.getHostName(), tmp.getPort()); - - // by the time we get here, we are connected - samples.add(System.currentTimeMillis() - start); - - // cleanup - socket.close(); - } - - // report - reporter.report(StatisticsHelper.process(samples), getName()); - } - } catch (TorCtlException | IOException e) { - e.printStackTrace(); - } - } -} diff --git a/monitor/src/main/java/bisq/monitor/metric/TorStartupTime.java b/monitor/src/main/java/bisq/monitor/metric/TorStartupTime.java deleted file mode 100644 index 9ea3198e197..00000000000 --- a/monitor/src/main/java/bisq/monitor/metric/TorStartupTime.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * This file is part of Bisq. - * - * Bisq is free software: you can redistribute it and/or modify it - * under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or (at - * your option) any later version. - * - * Bisq is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public - * License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with Bisq. If not, see . - */ - -package bisq.monitor.metric; - -import bisq.monitor.Metric; -import bisq.monitor.Reporter; - -import org.berndpruenster.netlayer.tor.NativeTor; -import org.berndpruenster.netlayer.tor.Tor; -import org.berndpruenster.netlayer.tor.TorCtlException; -import org.berndpruenster.netlayer.tor.Torrc; - -import java.io.File; -import java.io.IOException; - -import java.util.LinkedHashMap; -import java.util.Properties; - -/** - * A Metric to measure the deployment and startup time of the packaged Tor - * binaries. - * - * @author Florian Reimair - */ -public class TorStartupTime extends Metric { - - private static final String SOCKS_PORT = "run.socksPort"; - private final File torWorkingDirectory = new File("monitor/work/metric_torStartupTime"); - private Torrc torOverrides; - - public TorStartupTime(Reporter reporter) { - super(reporter); - } - - @Override - public void configure(Properties properties) { - super.configure(properties); - - synchronized (this) { - LinkedHashMap overrides = new LinkedHashMap<>(); - overrides.put("SOCKSPort", configuration.getProperty(SOCKS_PORT, "90500")); - - try { - torOverrides = new Torrc(overrides); - } catch (IOException e) { - e.printStackTrace(); - } - } - } - - @Override - protected void execute() { - // cleanup installation - torWorkingDirectory.delete(); - Tor tor = null; - // start timer - we do not need System.nanoTime as we expect our result to be in - // tenth of seconds time. - long start = System.currentTimeMillis(); - - try { - tor = new NativeTor(torWorkingDirectory, null, torOverrides); - - // stop the timer and set its timestamp - reporter.report(System.currentTimeMillis() - start, getName()); - } catch (TorCtlException e) { - e.printStackTrace(); - } finally { - // cleanup - if (tor != null) - tor.shutdown(); - } - } -} diff --git a/monitor/src/main/java/bisq/monitor/reporter/ConsoleReporter.java b/monitor/src/main/java/bisq/monitor/reporter/ConsoleReporter.java deleted file mode 100644 index f34dc2d5679..00000000000 --- a/monitor/src/main/java/bisq/monitor/reporter/ConsoleReporter.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * This file is part of Bisq. - * - * Bisq is free software: you can redistribute it and/or modify it - * under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or (at - * your option) any later version. - * - * Bisq is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public - * License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with Bisq. If not, see . - */ - -package bisq.monitor.reporter; - -import bisq.monitor.Reporter; - -import bisq.common.app.Version; -import bisq.common.config.BaseCurrencyNetwork; - -import java.util.HashMap; -import java.util.Map; - -/** - * A simple console reporter. - * - * @author Florian Reimair - */ -public class ConsoleReporter extends Reporter { - - @Override - public void report(long value, String prefix) { - HashMap result = new HashMap<>(); - result.put("", String.valueOf(value)); - report(result, prefix); - - } - - @Override - public void report(long value) { - HashMap result = new HashMap<>(); - result.put("", String.valueOf(value)); - report(result); - } - - @Override - public void report(Map values, String prefix) { - String timestamp = String.valueOf(System.currentTimeMillis()); - values.forEach((key, value) -> { - report(key, value, timestamp, prefix); - }); - } - - @Override - public void report(String key, String value, String timestamp, String prefix) { - System.err.println("Report: bisq" + (Version.getBaseCurrencyNetwork() != 0 ? "-" + BaseCurrencyNetwork.values()[Version.getBaseCurrencyNetwork()].getNetwork() : "") - + (prefix.isEmpty() ? "" : "." + prefix) - + (key.isEmpty() ? "" : "." + key) - + " " + value + " " + timestamp); - } - - @Override - public void report(Map values) { - report(values, ""); - } -} diff --git a/monitor/src/main/java/bisq/monitor/reporter/GraphiteReporter.java b/monitor/src/main/java/bisq/monitor/reporter/GraphiteReporter.java deleted file mode 100644 index dc0334ff40c..00000000000 --- a/monitor/src/main/java/bisq/monitor/reporter/GraphiteReporter.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - * This file is part of Bisq. - * - * Bisq is free software: you can redistribute it and/or modify it - * under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or (at - * your option) any later version. - * - * Bisq is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public - * License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with Bisq. If not, see . - */ - -package bisq.monitor.reporter; - -import bisq.monitor.OnionParser; -import bisq.monitor.Reporter; - -import bisq.network.p2p.NodeAddress; - -import bisq.common.app.Version; -import bisq.common.config.BaseCurrencyNetwork; - -import org.berndpruenster.netlayer.tor.TorSocket; - -import com.google.common.base.Charsets; - -import java.net.Socket; - -import java.io.IOException; - -import java.util.HashMap; -import java.util.Map; - -/** - * Reports our findings to a graphite service. - * - * @author Florian Reimair - */ -public class GraphiteReporter extends Reporter { - - @Override - public void report(long value, String prefix) { - HashMap result = new HashMap<>(); - result.put("", String.valueOf(value)); - report(result, prefix); - - } - - @Override - public void report(long value) { - report(value, ""); - } - - @Override - public void report(Map values, String prefix) { - String timestamp = String.valueOf(System.currentTimeMillis()); - values.forEach((key, value) -> { - - report(key, value, timestamp, prefix); - try { - // give Tor some slack - // TODO maybe use the pickle protocol? - // https://graphite.readthedocs.io/en/latest/feeding-carbon.html - Thread.sleep(100); - } catch (InterruptedException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - }); - } - - @Override - public void report(String key, String value, String timeInMilliseconds, String prefix) { - // https://graphite.readthedocs.io/en/latest/feeding-carbon.html - String report = "bisq" + (Version.getBaseCurrencyNetwork() != 0 ? "-" + BaseCurrencyNetwork.values()[Version.getBaseCurrencyNetwork()].getNetwork() : "") - + (prefix.isEmpty() ? "" : "." + prefix) - + (key.isEmpty() ? "" : "." + key) - + " " + value + " " + Long.parseLong(timeInMilliseconds) / 1000 + "\n"; - - try { - NodeAddress nodeAddress = OnionParser.getNodeAddress(configuration.getProperty("serviceUrl")); - Socket socket; - if (nodeAddress.getFullAddress().contains(".onion")) - socket = new TorSocket(nodeAddress.getHostName(), nodeAddress.getPort()); - else - socket = new Socket(nodeAddress.getHostName(), nodeAddress.getPort()); - - socket.getOutputStream().write(report.getBytes(Charsets.UTF_8)); - socket.close(); - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - - } - - @Override - public void report(Map values) { - report(values, ""); - } -} diff --git a/monitor/src/main/resources/logback.xml b/monitor/src/main/resources/logback.xml deleted file mode 100644 index 28831d6fc3b..00000000000 --- a/monitor/src/main/resources/logback.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n - - - - - - - - diff --git a/monitor/src/main/resources/metrics.properties b/monitor/src/main/resources/metrics.properties deleted file mode 100644 index 83a66920ca6..00000000000 --- a/monitor/src/main/resources/metrics.properties +++ /dev/null @@ -1,79 +0,0 @@ -## System configuration - -# true overwrites the reporters picked by the developers (for debugging for example) (defaults to false) -System.useConsoleReporter=true - -# 0 -> BTC_MAINNET, 1 -> BTC_TESTNET (default) -System.baseCurrencyNetwork=0 - -## Each Metric is configured via a set of properties. -## -## The minimal set of properties required to run a Metric is: -## -## YourMetricName.enabled=true|false -## YourMetricName.run.interval=10 [seconds] - -#Edit and uncomment the lines below to your liking - -#TorStartupTime Metric -TorStartupTime.enabled=false -TorStartupTime.run.interval=100 -TorStartupTime.run.socksPort=90500 - -TorRoundTripTime.enabled=false -TorRoundTripTime.run.interval=100 -TorRoundTripTime.run.sampleSize=3 -# torproject.org hidden service -TorRoundTripTime.run.hosts=http://expyuzz4wqqyqhjn.onion:80 - -#TorHiddenServiceStartupTime Metric -TorHiddenServiceStartupTime.enabled=false -TorHiddenServiceStartupTime.run.interval=100 -TorHiddenServiceStartupTime.run.localPort=90501 -TorHiddenServiceStartupTime.run.servicePort=90511 - -#P2PRoundTripTime Metric -P2PRoundTripTime.enabled=false -P2PRoundTripTime.run.interval=100 -P2PRoundTripTime.run.sampleSize=5 -P2PRoundTripTime.run.hosts=723ljisnynbtdohi.onion:8000, fl3mmribyxgrv63c.onion:8000 -P2PRoundTripTime.run.torProxyPort=9060 - -#P2PNetworkLoad Metric -P2PNetworkLoad.enabled=false -P2PNetworkLoad.run.interval=100 -P2PNetworkLoad.run.torProxyPort=9061 -P2PNetworkLoad.run.historySize=200 - -#P2PSeedNodeSnapshotBase Metric -P2PSeedNodeSnapshot.enabled=true -P2PSeedNodeSnapshot.run.dbDir=bisq/p2p/build/resources/main/ -P2PSeedNodeSnapshot.run.interval=24 -P2PSeedNodeSnapshot.run.hosts=3f3cu2yw7u457ztq.onion:8000, 723ljisnynbtdohi.onion:8000, fl3mmribyxgrv63c.onion:8000 -P2PSeedNodeSnapshot.run.torProxyPort=9062 - -#P2PMarketStats Metric -P2PMarketStats.enabled=false -P2PMarketStats.run.interval=37 -P2PMarketStats.run.dbDir=bisq/p2p/build/resources/main/ -P2PMarketStats.run.hosts=ef5qnzx6znifo3df.onion:8000 -P2PMarketStats.run.torProxyPort=9063 - -#PriceNodeStats Metric -PriceNodeStats.enabled=false -PriceNodeStats.run.interval=42 -PriceNodeStats.run.hosts=http://xc3nh4juf2hshy7e.onion, http://44mgyoe2b6oqiytt.onion, http://62nvujg5iou3vu3i.onion, http://ceaanhbvluug4we6.onion, http://gztmprecgqjq64zh.onion/ - -#MarketStats Metric -MarketStats.enabled=false -MarketStats.run.interval=191 - -#Another Metric -Another.run.interval=5 - -## Reporters are configured via a set of properties as well. -## -## In contrast to Metrics, Reporters do not have a minimal set of properties. - -#GraphiteReporter -GraphiteReporter.serviceUrl=k6evlhg44acpchtc.onion:2003 diff --git a/monitor/src/test/java/bisq/monitor/MonitorInfrastructureTests.java b/monitor/src/test/java/bisq/monitor/MonitorInfrastructureTests.java deleted file mode 100644 index 5e1fc248308..00000000000 --- a/monitor/src/test/java/bisq/monitor/MonitorInfrastructureTests.java +++ /dev/null @@ -1,149 +0,0 @@ -/* - * This file is part of Bisq. - * - * Bisq is free software: you can redistribute it and/or modify it - * under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or (at - * your option) any later version. - * - * Bisq is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public - * License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with Bisq. If not, see . - */ - -package bisq.monitor; - -import bisq.monitor.reporter.ConsoleReporter; - -import java.util.HashMap; -import java.util.Properties; -import java.util.concurrent.ExecutionException; - -import org.junit.Assert; -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.ValueSource; - -@Disabled -public class MonitorInfrastructureTests { - - /** - * A dummy metric for development purposes. - */ - public class Dummy extends Metric { - - public Dummy() { - super(new ConsoleReporter()); - } - - public boolean active() { - return enabled(); - } - - @Override - protected void execute() { - try { - Thread.sleep(50000); - - } catch (InterruptedException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - } - - @ParameterizedTest - @ValueSource(strings = {"empty", "no interval", "typo"}) - public void basicConfigurationError(String configuration) { - HashMap lut = new HashMap<>(); - lut.put("empty", new Properties()); - Properties noInterval = new Properties(); - noInterval.put("Dummy.enabled", "true"); - lut.put("no interval", noInterval); - Properties typo = new Properties(); - typo.put("Dummy.enabled", "true"); - //noinspection SpellCheckingInspection - typo.put("Dummy.run.inteval", "1"); - lut.put("typo", typo); - - Dummy DUT = new Dummy(); - DUT.configure(lut.get(configuration)); - Assert.assertFalse(DUT.active()); - } - - @Test - public void basicConfigurationSuccess() throws Exception { - Properties correct = new Properties(); - correct.put("Dummy.enabled", "true"); - correct.put("Dummy.run.interval", "1"); - - Dummy DUT = new Dummy(); - DUT.configure(correct); - Assert.assertTrue(DUT.active()); - - // graceful shutdown - Metric.haltAllMetrics(); - } - - @Test - public void reloadConfig() throws InterruptedException, ExecutionException { - // our dummy - Dummy DUT = new Dummy(); - - // a second dummy to run as well - Dummy DUT2 = new Dummy(); - DUT2.setName("Dummy2"); - Properties dummy2Properties = new Properties(); - dummy2Properties.put("Dummy2.enabled", "true"); - dummy2Properties.put("Dummy2.run.interval", "1"); - DUT2.configure(dummy2Properties); - - // disable - DUT.configure(new Properties()); - Assert.assertFalse(DUT.active()); - Assert.assertTrue(DUT2.active()); - - // enable - Properties properties = new Properties(); - properties.put("Dummy.enabled", "true"); - properties.put("Dummy.run.interval", "1"); - DUT.configure(properties); - Assert.assertTrue(DUT.active()); - Assert.assertTrue(DUT2.active()); - - // disable again - DUT.configure(new Properties()); - Assert.assertFalse(DUT.active()); - Assert.assertTrue(DUT2.active()); - - // enable again - DUT.configure(properties); - Assert.assertTrue(DUT.active()); - Assert.assertTrue(DUT2.active()); - - // graceful shutdown - Metric.haltAllMetrics(); - } - - @Test - public void shutdown() { - Dummy DUT = new Dummy(); - DUT.setName("Dummy"); - Properties dummyProperties = new Properties(); - dummyProperties.put("Dummy.enabled", "true"); - dummyProperties.put("Dummy.run.interval", "1"); - DUT.configure(dummyProperties); - try { - Thread.sleep(2000); - Metric.haltAllMetrics(); - } catch (InterruptedException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } -} diff --git a/monitor/src/test/java/bisq/monitor/P2PNetworkLoadTests.java b/monitor/src/test/java/bisq/monitor/P2PNetworkLoadTests.java deleted file mode 100644 index 25a11f976bc..00000000000 --- a/monitor/src/test/java/bisq/monitor/P2PNetworkLoadTests.java +++ /dev/null @@ -1,118 +0,0 @@ -/* - * This file is part of Bisq. - * - * Bisq is free software: you can redistribute it and/or modify it - * under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or (at - * your option) any later version. - * - * Bisq is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public - * License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with Bisq. If not, see . - */ - -package bisq.monitor; - -import bisq.monitor.metric.P2PNetworkLoad; -import bisq.monitor.reporter.ConsoleReporter; - -import org.berndpruenster.netlayer.tor.NativeTor; -import org.berndpruenster.netlayer.tor.Tor; -import org.berndpruenster.netlayer.tor.TorCtlException; - -import java.util.Map; -import java.util.Properties; - -import org.junit.Assert; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.Test; - -import static com.google.common.base.Preconditions.checkNotNull; - -/** - * Test the round trip time metric against the hidden service of tor project.org. - * - * @author Florian Reimair - */ -@Disabled -class P2PNetworkLoadTests { - - /** - * A dummy Reporter for development purposes. - */ - private class DummyReporter extends ConsoleReporter { - - private Map results; - - @Override - public void report(long value) { - Assert.fail(); - } - - Map hasResults() { - return results; - } - - @Override - public void report(Map values) { - Assert.fail(); - } - - @Override - public void report(long value, String prefix) { - Assert.fail(); - } - - @Override - public void report(Map values, String prefix) { - super.report(values, prefix); - results = values; - } - } - - @BeforeAll - static void setup() throws TorCtlException { - // simulate the tor instance available to all metrics - Tor.setDefault(new NativeTor(Monitor.TOR_WORKING_DIR)); - } - - @Test - void run() throws Exception { - DummyReporter reporter = new DummyReporter(); - - // configure - Properties configuration = new Properties(); - configuration.put("P2PNetworkLoad.enabled", "true"); - configuration.put("P2PNetworkLoad.run.interval", "10"); - configuration.put("P2PNetworkLoad.run.hosts", - "http://fl3mmribyxgrv63c.onion:8000, http://3f3cu2yw7u457ztq.onion:8000"); - - Metric DUT = new P2PNetworkLoad(reporter); - // start - DUT.configure(configuration); - - // give it some time to start and then stop - while (!DUT.enabled()) - Thread.sleep(500); - Thread.sleep(20000); - - Metric.haltAllMetrics(); - - // observe results - Map results = reporter.hasResults(); - Assert.assertFalse(results.isEmpty()); - } - - @AfterAll - static void cleanup() { - Tor tor = Tor.getDefault(); - checkNotNull(tor, "tor must not be null"); - tor.shutdown(); - } -} diff --git a/monitor/src/test/java/bisq/monitor/P2PRoundTripTimeTests.java b/monitor/src/test/java/bisq/monitor/P2PRoundTripTimeTests.java deleted file mode 100644 index a10dde58095..00000000000 --- a/monitor/src/test/java/bisq/monitor/P2PRoundTripTimeTests.java +++ /dev/null @@ -1,136 +0,0 @@ -/* - * This file is part of Bisq. - * - * Bisq is free software: you can redistribute it and/or modify it - * under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or (at - * your option) any later version. - * - * Bisq is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public - * License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with Bisq. If not, see . - */ - -package bisq.monitor; - -import bisq.monitor.metric.P2PRoundTripTime; -import bisq.monitor.reporter.ConsoleReporter; - -import org.berndpruenster.netlayer.tor.NativeTor; -import org.berndpruenster.netlayer.tor.Tor; -import org.berndpruenster.netlayer.tor.TorCtlException; - -import java.util.Map; -import java.util.Properties; - -import org.junit.Assert; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.ValueSource; - -import static com.google.common.base.Preconditions.checkNotNull; - -/** - * Test the round trip time metric against the hidden service of tor project.org. - * - * @author Florian Reimair - */ -@Disabled -class P2PRoundTripTimeTests { - - /** - * A dummy Reporter for development purposes. - */ - private class DummyReporter extends ConsoleReporter { - - private Map results; - - @Override - public void report(long value) { - Assert.fail(); - } - - Map hasResults() { - return results; - } - - @Override - public void report(Map values) { - Assert.fail(); - } - - @Override - public void report(long value, String prefix) { - Assert.fail(); - } - - @Override - public void report(Map values, String prefix) { - super.report(values, prefix); - results = values; - } - } - - @BeforeAll - static void setup() throws TorCtlException { - // simulate the tor instance available to all metrics - Tor.setDefault(new NativeTor(Monitor.TOR_WORKING_DIR)); - } - - @ParameterizedTest - @ValueSource(strings = {"default", "3", "4", "10"}) - void run(String sampleSize) throws Exception { - DummyReporter reporter = new DummyReporter(); - - // configure - Properties configuration = new Properties(); - configuration.put("P2PRoundTripTime.enabled", "true"); - configuration.put("P2PRoundTripTime.run.interval", "2"); - if (!"default".equals(sampleSize)) - configuration.put("P2PRoundTripTime.run.sampleSize", sampleSize); - // torproject.org hidden service - configuration.put("P2PRoundTripTime.run.hosts", "http://fl3mmribyxgrv63c.onion:8000"); - configuration.put("P2PRoundTripTime.run.torProxyPort", "9052"); - - Metric DUT = new P2PRoundTripTime(reporter); - // start - DUT.configure(configuration); - - // give it some time to start and then stop - while (!DUT.enabled()) - Thread.sleep(2000); - - Metric.haltAllMetrics(); - - // observe results - Map results = reporter.hasResults(); - Assert.assertFalse(results.isEmpty()); - Assert.assertEquals(results.get("sampleSize"), sampleSize.equals("default") ? "1" : sampleSize); - - Integer p25 = Integer.valueOf(results.get("p25")); - Integer p50 = Integer.valueOf(results.get("p50")); - Integer p75 = Integer.valueOf(results.get("p75")); - Integer min = Integer.valueOf(results.get("min")); - Integer max = Integer.valueOf(results.get("max")); - Integer average = Integer.valueOf(results.get("average")); - - Assert.assertTrue(0 < min); - Assert.assertTrue(min <= p25 && p25 <= p50); - Assert.assertTrue(p50 <= p75); - Assert.assertTrue(p75 <= max); - Assert.assertTrue(min <= average && average <= max); - } - - @AfterAll - static void cleanup() { - Tor tor = Tor.getDefault(); - checkNotNull(tor, "tor must not be null"); - tor.shutdown(); - } -} diff --git a/monitor/src/test/java/bisq/monitor/PriceNodeStatsTests.java b/monitor/src/test/java/bisq/monitor/PriceNodeStatsTests.java deleted file mode 100644 index b424b9878df..00000000000 --- a/monitor/src/test/java/bisq/monitor/PriceNodeStatsTests.java +++ /dev/null @@ -1,115 +0,0 @@ -/* - * This file is part of Bisq. - * - * Bisq is free software: you can redistribute it and/or modify it - * under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or (at - * your option) any later version. - * - * Bisq is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public - * License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with Bisq. If not, see . - */ - -package bisq.monitor; - -import bisq.monitor.metric.PriceNodeStats; - -import org.berndpruenster.netlayer.tor.NativeTor; -import org.berndpruenster.netlayer.tor.Tor; -import org.berndpruenster.netlayer.tor.TorCtlException; - -import java.io.File; - -import java.util.Map; -import java.util.Properties; - -import org.junit.Assert; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.Test; - -import static com.google.common.base.Preconditions.checkNotNull; - -/** - * @author Florian Reimair - */ -@Disabled -public class PriceNodeStatsTests { - - private final static File torWorkingDirectory = new File("monitor/" + PriceNodeStatsTests.class.getSimpleName()); - - /** - * A dummy Reporter for development purposes. - */ - private class DummyReporter extends Reporter { - - private Map results; - - @Override - public void report(long value) { - Assert.fail(); - } - - public Map results() { - return results; - } - - @Override - public void report(Map values) { - results = values; - } - - @Override - public void report(Map values, String prefix) { - report(values); - } - - @Override - public void report(String key, String value, String timestamp, String prefix) { - - } - - @Override - public void report(long value, String prefix) { - report(value); - } - } - - @BeforeAll - public static void setup() throws TorCtlException { - // simulate the tor instance available to all metrics - Tor.setDefault(new NativeTor(torWorkingDirectory)); - } - - @Test - public void connect() { - DummyReporter reporter = new DummyReporter(); - Metric DUT = new PriceNodeStats(reporter); - - - Properties configuration = new Properties(); - configuration.put("PriceNodeStats.run.hosts", "http://5bmpx76qllutpcyp.onion"); - - DUT.configure(configuration); - - DUT.execute(); - - Assert.assertNotNull(reporter.results()); - Assert.assertTrue(reporter.results.size() > 0); - } - - @AfterAll - public static void cleanup() { - Tor tor = Tor.getDefault(); - checkNotNull(tor, "tor must not be null"); - tor.shutdown(); - torWorkingDirectory.delete(); - } - -} diff --git a/monitor/src/test/java/bisq/monitor/TorHiddenServiceStartupTimeTests.java b/monitor/src/test/java/bisq/monitor/TorHiddenServiceStartupTimeTests.java deleted file mode 100644 index d517bcd5659..00000000000 --- a/monitor/src/test/java/bisq/monitor/TorHiddenServiceStartupTimeTests.java +++ /dev/null @@ -1,115 +0,0 @@ -/* - * This file is part of Bisq. - * - * Bisq is free software: you can redistribute it and/or modify it - * under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or (at - * your option) any later version. - * - * Bisq is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public - * License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with Bisq. If not, see . - */ - -package bisq.monitor; - -import bisq.monitor.metric.TorHiddenServiceStartupTime; - -import org.berndpruenster.netlayer.tor.NativeTor; -import org.berndpruenster.netlayer.tor.Tor; -import org.berndpruenster.netlayer.tor.TorCtlException; - -import java.io.File; - -import java.util.Map; -import java.util.Properties; - -import org.junit.Assert; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.Test; - -import static com.google.common.base.Preconditions.checkNotNull; - -@Disabled // Ignore for normal test runs as the tests take lots of time -public class TorHiddenServiceStartupTimeTests { - - private final static File torWorkingDirectory = new File("monitor/" + TorHiddenServiceStartupTimeTests.class.getSimpleName()); - - /** - * A dummy Reporter for development purposes. - */ - private class DummyReporter extends Reporter { - - private long result; - - @Override - public void report(long value) { - result = value; - } - - public long results() { - return result; - } - - @Override - public void report(Map values) { - report(Long.parseLong(values.values().iterator().next())); - } - - @Override - public void report(Map values, String prefix) { - report(values); - } - - @Override - public void report(String key, String value, String timestamp, String prefix) { - - } - - @Override - public void report(long value, String prefix) { - report(value); - } - } - - @BeforeAll - public static void setup() throws TorCtlException { - // simulate the tor instance available to all metrics - Tor.setDefault(new NativeTor(torWorkingDirectory)); - } - - @Test - public void run() throws Exception { - DummyReporter reporter = new DummyReporter(); - - // configure - Properties configuration = new Properties(); - configuration.put("TorHiddenServiceStartupTime.enabled", "true"); - configuration.put("TorHiddenServiceStartupTime.run.interval", "5"); - - Metric DUT = new TorHiddenServiceStartupTime(reporter); - // start - DUT.configure(configuration); - - // give it some time and then stop - Thread.sleep(180 * 1000); - Metric.haltAllMetrics(); - - // observe results - Assert.assertTrue(reporter.results() > 0); - } - - @AfterAll - public static void cleanup() { - Tor tor = Tor.getDefault(); - checkNotNull(tor, "tor must not be null"); - tor.shutdown(); - torWorkingDirectory.delete(); - } -} diff --git a/monitor/src/test/java/bisq/monitor/TorRoundTripTimeTests.java b/monitor/src/test/java/bisq/monitor/TorRoundTripTimeTests.java deleted file mode 100644 index b2091806a48..00000000000 --- a/monitor/src/test/java/bisq/monitor/TorRoundTripTimeTests.java +++ /dev/null @@ -1,142 +0,0 @@ -/* - * This file is part of Bisq. - * - * Bisq is free software: you can redistribute it and/or modify it - * under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or (at - * your option) any later version. - * - * Bisq is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public - * License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with Bisq. If not, see . - */ - -package bisq.monitor; - -import bisq.monitor.metric.TorRoundTripTime; - -import org.berndpruenster.netlayer.tor.NativeTor; -import org.berndpruenster.netlayer.tor.Tor; -import org.berndpruenster.netlayer.tor.TorCtlException; - -import java.io.File; - -import java.util.Map; -import java.util.Properties; - -import org.junit.Assert; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.ValueSource; - -import static com.google.common.base.Preconditions.checkNotNull; - -/** - * Test the round trip time metric against the hidden service of tor project.org. - * - * @author Florian Reimair - */ -@Disabled // Ignore for normal test runs as the tests take lots of time -public class TorRoundTripTimeTests { - - /** - * A dummy Reporter for development purposes. - */ - private class DummyReporter extends Reporter { - - private Map results; - - @Override - public void report(long value) { - Assert.fail(); - } - - public Map hasResults() { - return results; - } - - @Override - public void report(Map values) { - results = values; - } - - @Override - public void report(Map values, String prefix) { - report(values); - } - - @Override - public void report(String key, String value, String timestamp, String prefix) { - - } - - @Override - public void report(long value, String prefix) { - report(value); - } - } - - private static final File workingDirectory = new File(TorRoundTripTimeTests.class.getSimpleName()); - - @BeforeAll - public static void setup() throws TorCtlException { - // simulate the tor instance available to all metrics - Tor.setDefault(new NativeTor(workingDirectory)); - } - - @ParameterizedTest - @ValueSource(strings = {"default", "3", "4", "10"}) - public void run(String sampleSize) throws Exception { - DummyReporter reporter = new DummyReporter(); - - // configure - Properties configuration = new Properties(); - configuration.put("TorRoundTripTime.enabled", "true"); - configuration.put("TorRoundTripTime.run.interval", "2"); - if (!"default".equals(sampleSize)) - configuration.put("TorRoundTripTime.run.sampleSize", sampleSize); - // torproject.org hidden service - configuration.put("TorRoundTripTime.run.hosts", "http://expyuzz4wqqyqhjn.onion:80"); - - Metric DUT = new TorRoundTripTime(reporter); - // start - DUT.configure(configuration); - - // give it some time to start and then stop - Thread.sleep(100); - - Metric.haltAllMetrics(); - - // observe results - Map results = reporter.hasResults(); - Assert.assertFalse(results.isEmpty()); - Assert.assertEquals(results.get("sampleSize"), sampleSize.equals("default") ? "1" : sampleSize); - - Integer p25 = Integer.valueOf(results.get("p25")); - Integer p50 = Integer.valueOf(results.get("p50")); - Integer p75 = Integer.valueOf(results.get("p75")); - Integer min = Integer.valueOf(results.get("min")); - Integer max = Integer.valueOf(results.get("max")); - Integer average = Integer.valueOf(results.get("average")); - - Assert.assertTrue(0 < min); - Assert.assertTrue(min <= p25 && p25 <= p50); - Assert.assertTrue(p50 <= p75); - Assert.assertTrue(p75 <= max); - Assert.assertTrue(min <= average && average <= max); - } - - @AfterAll - public static void cleanup() { - Tor tor = Tor.getDefault(); - checkNotNull(tor, "tor must not be null"); - tor.shutdown(); - workingDirectory.delete(); - } -} diff --git a/monitor/src/test/java/bisq/monitor/TorStartupTimeTests.java b/monitor/src/test/java/bisq/monitor/TorStartupTimeTests.java deleted file mode 100644 index e72325c847a..00000000000 --- a/monitor/src/test/java/bisq/monitor/TorStartupTimeTests.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * This file is part of Bisq. - * - * Bisq is free software: you can redistribute it and/or modify it - * under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or (at - * your option) any later version. - * - * Bisq is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public - * License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with Bisq. If not, see . - */ - -package bisq.monitor; - -import bisq.monitor.metric.TorStartupTime; - -import java.util.Map; -import java.util.Properties; - -import org.junit.Assert; -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.Test; - -@Disabled // Ignore for normal test runs as the tests take lots of time -public class TorStartupTimeTests { - - /** - * A dummy Reporter for development purposes. - */ - private class DummyReporter extends Reporter { - - private long result; - - @Override - public void report(long value) { - result = value; - } - - public long results() { - return result; - } - - @Override - public void report(Map values) { - report(Long.parseLong(values.values().iterator().next())); - } - - @Override - public void report(Map values, String prefix) { - report(values); - } - - @Override - public void report(String key, String value, String timestamp, String prefix) { - - } - - @Override - public void report(long value, String prefix) { - report(value); - } - } - - @Test - public void run() throws Exception { - - DummyReporter reporter = new DummyReporter(); - - // configure - Properties configuration = new Properties(); - configuration.put("TorStartupTime.enabled", "true"); - configuration.put("TorStartupTime.run.interval", "2"); - configuration.put("TorStartupTime.run.socksPort", "9999"); - - Metric DUT = new TorStartupTime(reporter); - // start - DUT.configure(configuration); - - // give it some time and then stop - Thread.sleep(15 * 1000); - Metric.haltAllMetrics(); - - // TODO Test fails due timing issue - // observe results - Assert.assertTrue(reporter.results() > 0); - } -} diff --git a/monitor/uninstall_collectd_debian.sh b/monitor/uninstall_collectd_debian.sh deleted file mode 100755 index dc63b4cc00d..00000000000 --- a/monitor/uninstall_collectd_debian.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/sh -echo "[*] Stopping Bisq Server monitoring utensils" -echo ' ' -echo 'This script will not remove any configuration or binaries from the system. It just stops the services.' - -sleep 10 -sudo systemctl stop nginx -sudo systemctl stop collectd -sudo systemctl disable nginx -sudo systemctl disable collectd -echo "[*] Done!" diff --git a/settings.gradle b/settings.gradle index b9c33414f19..bd203e742e9 100644 --- a/settings.gradle +++ b/settings.gradle @@ -6,7 +6,6 @@ include 'core' include 'cli' include 'daemon' include 'desktop' -include 'monitor' include 'seednode' include 'statsnode' include 'apitest'