Add inventory module and dependencies

This commit is contained in:
HenrikJannsen 2024-06-02 13:38:25 +07:00
parent 492e91c0cb
commit 32a8091484
No known key found for this signature in database
GPG Key ID: 02AA2BAE387C8307
10 changed files with 1420 additions and 3 deletions

View File

@ -43,9 +43,12 @@ natpryce-make-it-easy = { strictly = '4.0.1' }
netlayer = { strictly = '2b459dc' }
openjfx-javafx-plugin = { strictly = '0.0.10' }
protobuf = { strictly = '3.19.1' }
pushy = { strictly = '0.13.2' }
qrgen = { strictly = '1.3' }
javacv = { strictly = '1.5.10' }
slf4j = { strictly = '1.7.30' }
spark = { strictly = '2.5.2' }
[libraries]
apache-httpclient = { module = "org.apache.httpcomponents:httpclient", version.ref = "apache-httpclient" }
@ -75,6 +78,7 @@ grpc-core = { module = "io.grpc:grpc-core", version.ref = "grpc" }
grpc-netty-shaded = { module = "io.grpc:grpc-netty-shaded", version.ref = "grpc" }
grpc-protobuf = { module = "io.grpc:grpc-protobuf", version.ref = "grpc" }
grpc-stub = { module = "io.grpc:grpc-stub", version.ref = "grpc" }
grpc-auth = { module = "io.grpc:grpc-auth", version.ref = "grpc" }
hamcrest = { module = "org.hamcrest:hamcrest", version.ref = "hamcrest" }
@ -108,6 +112,9 @@ netlayer-tor-native = { module = "com.github.bisq-network.netlayer:tor.native",
openjfx-javafx-plugin = { module = "org.openjfx:javafx-plugin", version.ref = "openjfx-javafx-plugin" }
protobuf-java = { module = "com.google.protobuf:protobuf-java", version.ref = "protobuf" }
pushy = { module = "com.turo:pushy", version.ref = "pushy" }
qrgen = { module = "net.glxn:qrgen", version.ref = "qrgen" }
javacv = { module = "org.bytedeco:javacv-platform", version.ref = "javacv" }
slf4j-api = { module = "org.slf4j:slf4j-api", version.ref = "slf4j" }
spark-core = { module = "com.sparkjava:spark-core", version.ref = "spark" }

View File

@ -38,6 +38,16 @@
<sha256 value="ec6a3b1ccb21e66c02e36899735c0c2171c5bd3a4ea269a28be95f9f2e8a822b" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="com.eatthepath" name="fast-uuid" version="0.1">
<artifact name="fast-uuid-0.1.jar">
<sha256 value="670976cae3f41609128f647388791f43af361f3e7403ef0e3f0529c23fa1bccc"
origin="Generated by Gradle"/>
</artifact>
<artifact name="fast-uuid-0.1.pom">
<sha256 value="8f51f3c717831493529c962e65dde7a4d51762a1818d7bb8777123635b669d9d"
origin="Generated by Gradle"/>
</artifact>
</component>
<component group="com.fasterxml" name="oss-parent" version="41">
<artifact name="oss-parent-41.pom">
<sha256 value="af650fa4dd400bc5769320bcef08ed93813f349cabe8213d469acafbbd945d8a" origin="Generated by Gradle"/>
@ -279,6 +289,22 @@
<artifact name="proto-google-common-protos-2.0.1.pom">
<sha256 value="8b62bfd85d693ebcffd828232af7424f34fd212c5e28e5ed99b0dc5d2bc7d4f5" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="com.google.auth" name="google-auth-library-credentials" version="0.22.2">
<artifact name="google-auth-library-credentials-0.22.2.jar">
<sha256 value="e42c2cbe642744f55bd2a081e6f60f126e691129e7148daec3af79deab4ac65a"
origin="Generated by Gradle"/>
</artifact>
<artifact name="google-auth-library-credentials-0.22.2.pom">
<sha256 value="c6094e9b3875421e8f4433d624b80df29f2aefc224f1238ffbf5e86cc89c1760"
origin="Generated by Gradle"/>
</artifact>
</component>
<component group="com.google.auth" name="google-auth-library-parent" version="0.22.2">
<artifact name="google-auth-library-parent-0.22.2.pom">
<sha256 value="6ea6b8eb596209e74d5a82b67e13f717ad6d788abe137f361d5137d457794e87"
origin="Generated by Gradle"/>
</artifact>
</component>
<component group="com.google.code.findbugs" name="jsr305" version="3.0.2">
<artifact name="jsr305-3.0.2.jar">
@ -501,6 +527,12 @@
<artifact name="listenablefuture-9999.0-empty-to-avoid-conflict-with-guava.pom">
<sha256 value="18d4b1db26153d4e55079ce1f76bb1fe05cdb862ef9954a88cbcc4ff38b8679b" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="com.google.http-client" name="google-http-client-bom" version="1.38.0">
<artifact name="google-http-client-bom-1.38.0.pom">
<sha256 value="c443a88cd51ce7714e7df9598267eb7d1c429caa56db4df016c8d3cef98d274d"
origin="Generated by Gradle"/>
</artifact>
</component>
<component group="com.google.inject" name="guice" version="5.0.1">
<artifact name="guice-5.0.1.jar">
@ -635,6 +667,32 @@
<sha256 value="1526287fb2372207be56c8e98b6a1621db9a88774331ba0c603b2710ed365f7d" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="com.sparkjava" name="spark-core" version="2.5.2">
<artifact name="spark-core-2.5.2.jar">
<sha256 value="76c246771297ebb14196eb2be621a1ab2d5b15d3038cb69f3becff1193e176bc"
origin="Generated by Gradle"/>
</artifact>
<artifact name="spark-core-2.5.2.pom">
<sha256 value="23cc86e685116e709d77f2fce2190b7978ac8a0002bd592c8aec1f03094b00f1"
origin="Generated by Gradle"/>
</artifact>
</component>
<component group="com.turo" name="pushy" version="0.13.2">
<artifact name="pushy-0.13.2.jar">
<sha256 value="6125ccbad18bdaf92b483e076b990bfd25da24bdb5bcb087308a31890a30911b"
origin="Generated by Gradle"/>
</artifact>
<artifact name="pushy-0.13.2.pom">
<sha256 value="b8955ece6942a0e978ae3d208b4508d65bb27231645c1c52699df940daf968d9"
origin="Generated by Gradle"/>
</artifact>
</component>
<component group="com.turo" name="pushy-parent" version="0.13.2">
<artifact name="pushy-parent-0.13.2.pom">
<sha256 value="2b0e8eeae3ac045f03faae0d7c2b791b65050632acd8463bce9b3b6de4ff9b2f"
origin="Generated by Gradle"/>
</artifact>
</component>
<component group="commons-codec" name="commons-codec" version="1.13">
<artifact name="commons-codec-1.13.jar">
<sha256 value="61f7a3079e92b9fdd605238d0295af5fd11ac411a0a0af48deace1f6c5ffa072" origin="Generated by Gradle"/>
@ -720,6 +778,16 @@
<sha256 value="e371abe8a43de8416afa1a970466d833d1974f86ed620a5f548ab5aac4610188" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="io.grpc" name="grpc-auth" version="1.42.1">
<artifact name="grpc-auth-1.42.1.jar">
<sha256 value="fbfeae9b1b8b913f82a8ed5c20d4536a404464bfd385fd8ecd5a7dac9207ce30"
origin="Generated by Gradle"/>
</artifact>
<artifact name="grpc-auth-1.42.1.pom">
<sha256 value="a9dc9340d89c6ebc1f4534cc911f129bb9413bccdbd95f76122e119e9dfdaab5"
origin="Generated by Gradle"/>
</artifact>
</component>
<component group="io.grpc" name="grpc-context" version="1.42.1">
<artifact name="grpc-context-1.42.1.jar">
<sha256 value="8810d6dc294b8c025c152a0093a2c62406ed79778f52ebbb28ab51640c1a4504" origin="Generated by Gradle"/>
@ -785,6 +853,132 @@
<sha256 value="9856d0a3e07df312825e698082b6ec6401cd15814ca74092ae58084f4925e784" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="io.netty" name="netty-buffer" version="4.1.25.Final">
<artifact name="netty-buffer-4.1.25.Final.jar">
<sha256 value="6adf1adb0a89b44c870b4773996679e6736f3b8f40cedb41e8c3e77e75d3619a"
origin="Generated by Gradle"/>
</artifact>
<artifact name="netty-buffer-4.1.25.Final.pom">
<sha256 value="c08ca134d93527a09e5a194cc4e92759fa459bd53f47835bd28d1f8f5504cf54"
origin="Generated by Gradle"/>
</artifact>
</component>
<component group="io.netty" name="netty-codec" version="4.1.25.Final">
<artifact name="netty-codec-4.1.25.Final.jar">
<sha256 value="c9c4bf830cb3284028317cb2752f7de54ecddab0142fc7c09cc3ddee0c6c100a"
origin="Generated by Gradle"/>
</artifact>
<artifact name="netty-codec-4.1.25.Final.pom">
<sha256 value="64116b0b2d5e68b74216e2b8abe1c0122513554a2d9f001f0d0508a91b635bcb"
origin="Generated by Gradle"/>
</artifact>
</component>
<component group="io.netty" name="netty-codec-dns" version="4.1.25.Final">
<artifact name="netty-codec-dns-4.1.25.Final.jar">
<sha256 value="6c41675e1dbaccfdef9295078917381ea5efd607d4ef92145f632b514de79a44"
origin="Generated by Gradle"/>
</artifact>
<artifact name="netty-codec-dns-4.1.25.Final.pom">
<sha256 value="71d0805a3404ddba9213d482157c92f619045532a6cbb21e172382873f148c53"
origin="Generated by Gradle"/>
</artifact>
</component>
<component group="io.netty" name="netty-codec-http" version="4.1.25.Final">
<artifact name="netty-codec-http-4.1.25.Final.jar">
<sha256 value="77fc6fa42dffe37fac5097d6bc5c546de941ed02972806ffd8d80efb3151d32d"
origin="Generated by Gradle"/>
</artifact>
<artifact name="netty-codec-http-4.1.25.Final.pom">
<sha256 value="2d01cae5cb0386450e130548e5202dcd97887c11af3ec7ce913e5883cc774164"
origin="Generated by Gradle"/>
</artifact>
</component>
<component group="io.netty" name="netty-codec-http2" version="4.1.25.Final">
<artifact name="netty-codec-http2-4.1.25.Final.jar">
<sha256 value="54f4f0012e9404cac014e63b85a72dd4ada89ea208d46969fe5c2b757f55ff40"
origin="Generated by Gradle"/>
</artifact>
<artifact name="netty-codec-http2-4.1.25.Final.pom">
<sha256 value="a869d53ec32fe87d3561dbec68f7c0801187a473659872e1e517ce5e33c3e4b5"
origin="Generated by Gradle"/>
</artifact>
</component>
<component group="io.netty" name="netty-codec-socks" version="4.1.25.Final">
<artifact name="netty-codec-socks-4.1.25.Final.jar">
<sha256 value="df75b12f37e00b65357fb41376c9f98bbedd9b7ee60dad0dfef8544ce14f65ea"
origin="Generated by Gradle"/>
</artifact>
<artifact name="netty-codec-socks-4.1.25.Final.pom">
<sha256 value="4a1032b7d1c6b83aa7d75ddaf19721caced5f69d788602f7153b7739b39f1151"
origin="Generated by Gradle"/>
</artifact>
</component>
<component group="io.netty" name="netty-common" version="4.1.25.Final">
<artifact name="netty-common-4.1.25.Final.jar">
<sha256 value="50697918592b03624d9a6ea1847d3a831d988d17bd44df370113c83dfda6095b"
origin="Generated by Gradle"/>
</artifact>
<artifact name="netty-common-4.1.25.Final.pom">
<sha256 value="20b49d4e77e78623826f931fbcf09e563fbe47062a9d2c9ac4df4dd3684dc57b"
origin="Generated by Gradle"/>
</artifact>
</component>
<component group="io.netty" name="netty-handler" version="4.1.25.Final">
<artifact name="netty-handler-4.1.25.Final.jar">
<sha256 value="98c45605619a571a75ce82ea49e7c54b2bb2eb5d4ddc3e327ae4559b82b8556a"
origin="Generated by Gradle"/>
</artifact>
<artifact name="netty-handler-4.1.25.Final.pom">
<sha256 value="f605af77b605ce5ba05919b84bb84f8d64218a2e93c9e55502eb52974fb8dc3c"
origin="Generated by Gradle"/>
</artifact>
</component>
<component group="io.netty" name="netty-handler-proxy" version="4.1.25.Final">
<artifact name="netty-handler-proxy-4.1.25.Final.jar">
<sha256 value="60952dc844c5d247fffafa0d78b05ca575cd6bf3ca753a132adb097c548da7d8"
origin="Generated by Gradle"/>
</artifact>
<artifact name="netty-handler-proxy-4.1.25.Final.pom">
<sha256 value="74c962cc24d2249d85f757fdc48deb7064e2a3ce2fa3a57cf557354e14007e6d"
origin="Generated by Gradle"/>
</artifact>
</component>
<component group="io.netty" name="netty-parent" version="4.1.25.Final">
<artifact name="netty-parent-4.1.25.Final.pom">
<sha256 value="fc637d287365b4a093e0bb48fe4689f45f04f924487e4cd84771d3abde562d6c"
origin="Generated by Gradle"/>
</artifact>
</component>
<component group="io.netty" name="netty-resolver" version="4.1.25.Final">
<artifact name="netty-resolver-4.1.25.Final.jar">
<sha256 value="85ea31999ad2cdbaa2f251caf2660a8ef0d9f274b0d86771077e7fd69c02b257"
origin="Generated by Gradle"/>
</artifact>
<artifact name="netty-resolver-4.1.25.Final.pom">
<sha256 value="73370505a346ef0de01a88dee28bcd580c9ebfad8a34ebb1f588b44ac036e4fc"
origin="Generated by Gradle"/>
</artifact>
</component>
<component group="io.netty" name="netty-resolver-dns" version="4.1.25.Final">
<artifact name="netty-resolver-dns-4.1.25.Final.jar">
<sha256 value="e2bb6ab70f3d3872e55e3127449fa6a2ee8c1a1b9a85b01ac9749fe1f6a0cfd8"
origin="Generated by Gradle"/>
</artifact>
<artifact name="netty-resolver-dns-4.1.25.Final.pom">
<sha256 value="968ecff379b6a854918613a1b4c039921b3718f9b3b265b33f8e4f7c5bba1495"
origin="Generated by Gradle"/>
</artifact>
</component>
<component group="io.netty" name="netty-transport" version="4.1.25.Final">
<artifact name="netty-transport-4.1.25.Final.jar">
<sha256 value="278b12a6f2c479124ff44c299c67d50443636ffed6399ae67d71473736cec58d"
origin="Generated by Gradle"/>
</artifact>
<artifact name="netty-transport-4.1.25.Final.pom">
<sha256 value="c349608aed8221909b1f84e46a14d7457eba0b2cd5e5c6bcb51ce784875e6b81"
origin="Generated by Gradle"/>
</artifact>
</component>
<component group="io.perfmark" name="perfmark-api" version="0.23.0">
<artifact name="perfmark-api-0.23.0.jar">
<sha256 value="c705b5c10c18ff3032b9e81742bc2f6b0e5607f6a6dfc0c8ad0cff75d4913042" origin="Generated by Gradle"/>
@ -808,6 +1002,16 @@
<artifact name="javax.inject-1.pom">
<sha256 value="943e12b100627804638fa285805a0ab788a680266531e650921ebfe4621a8bfa" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="javax.servlet" name="javax.servlet-api" version="3.1.0">
<artifact name="javax.servlet-api-3.1.0.jar">
<sha256 value="af456b2dd41c4e82cf54f3e743bc678973d9fe35bd4d3071fa05c7e5333b8482"
origin="Generated by Gradle"/>
</artifact>
<artifact name="javax.servlet-api-3.1.0.pom">
<sha256 value="b31109e22ea3f2df1ad7955432e718a35def50ae6c19698034afa8a0cf9e9069"
origin="Generated by Gradle"/>
</artifact>
</component>
<component group="junit" name="junit" version="4.12">
<artifact name="junit-4.12.jar">
@ -1831,6 +2035,154 @@
<artifact name="plexus-utils-3.0.24.pom">
<sha256 value="11067f6a75fded12bcdc8daf7a66ddd942ce289c3daf88a3fe0f8b12858a2ee6" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.eclipse.jetty" name="jetty-http" version="9.3.6.v20151106">
<artifact name="jetty-http-9.3.6.v20151106.jar">
<sha256 value="f0bb475e064671ccd75fc89edae5f3f718139189e5e09e672cb4fc3784215d1b"
origin="Generated by Gradle"/>
</artifact>
<artifact name="jetty-http-9.3.6.v20151106.pom">
<sha256 value="60adc7c0614f46d0fc2ec59d637d11df50b02277530d09df5ef188497058e3cd"
origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.eclipse.jetty" name="jetty-io" version="9.3.6.v20151106">
<artifact name="jetty-io-9.3.6.v20151106.jar">
<sha256 value="8ece9bf183c6c2d6c5036d7664d450cf9897f0e5aacb8f3dae092db7cf7848ec"
origin="Generated by Gradle"/>
</artifact>
<artifact name="jetty-io-9.3.6.v20151106.pom">
<sha256 value="bff43d1881565a84111358449591d854e7c36d7c078338bcf1a484afb7ae53a6"
origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.eclipse.jetty" name="jetty-parent" version="25">
<artifact name="jetty-parent-25.pom">
<sha256 value="d6d9cc8ea606d1c2e22d8101d92243ffccfdc4998935a99c459b9d9b1a14ba6c"
origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.eclipse.jetty" name="jetty-project" version="9.3.6.v20151106">
<artifact name="jetty-project-9.3.6.v20151106.pom">
<sha256 value="ecdb3554dc53490b385486d8c85d43c762602053814f267e6307888e606fb616"
origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.eclipse.jetty" name="jetty-security" version="9.3.6.v20151106">
<artifact name="jetty-security-9.3.6.v20151106.jar">
<sha256 value="d9729341568a245f3c028991c328e5fce35294f026fdfb9e2ab628ff34975fb5"
origin="Generated by Gradle"/>
</artifact>
<artifact name="jetty-security-9.3.6.v20151106.pom">
<sha256 value="8e21f15c54b904b7170221e2142db9ce8bfb8d60d4d86b8fce09c98572fc5c0b"
origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.eclipse.jetty" name="jetty-server" version="9.3.6.v20151106">
<artifact name="jetty-server-9.3.6.v20151106.jar">
<sha256 value="2277b6211e1db363d0cb22317f49906cd906dd47ca93f397cffead618dc052ea"
origin="Generated by Gradle"/>
</artifact>
<artifact name="jetty-server-9.3.6.v20151106.pom">
<sha256 value="5381892323929d0367d6c90efc0b808ba871e59ed536425a448ec0e0f8f9c64f"
origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.eclipse.jetty" name="jetty-servlet" version="9.3.6.v20151106">
<artifact name="jetty-servlet-9.3.6.v20151106.jar">
<sha256 value="4aabcb8c4b32918cdc66f6b4e48ba08276559f3d3eba6919cb49c221d08bb7f9"
origin="Generated by Gradle"/>
</artifact>
<artifact name="jetty-servlet-9.3.6.v20151106.pom">
<sha256 value="ed9b9ebfe9ac1153623288846d645fed319c3b33ee6586feef06b606640336c0"
origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.eclipse.jetty" name="jetty-util" version="9.3.6.v20151106">
<artifact name="jetty-util-9.3.6.v20151106.jar">
<sha256 value="3149d7cb665e3b7a37809fb9915a4c4ef190ec3d2d80d6c15207bde075224304"
origin="Generated by Gradle"/>
</artifact>
<artifact name="jetty-util-9.3.6.v20151106.pom">
<sha256 value="f1244c89163b51d8e8456668c57e4c1490340a3e3e0c1be8040a19113a0a16e0"
origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.eclipse.jetty" name="jetty-webapp" version="9.3.6.v20151106">
<artifact name="jetty-webapp-9.3.6.v20151106.jar">
<sha256 value="2e1805b52831dc88d2c19f1ee660609f337e2ec3007c9931dac65b7867f4aff1"
origin="Generated by Gradle"/>
</artifact>
<artifact name="jetty-webapp-9.3.6.v20151106.pom">
<sha256 value="eafd83acd89e883e4e0329fa6fdfb6149ccb61c26d86a8b6e82bc9815bf77842"
origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.eclipse.jetty" name="jetty-xml" version="9.3.6.v20151106">
<artifact name="jetty-xml-9.3.6.v20151106.jar">
<sha256 value="58a7c092323e9bff29fa7cd9ca072f5d7fb8e5806342c941b9780c5cbfcaf112"
origin="Generated by Gradle"/>
</artifact>
<artifact name="jetty-xml-9.3.6.v20151106.pom">
<sha256 value="7010066948db798bea3397eb26e1ef7ff32c3020fad234128699018f1e5e9647"
origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.eclipse.jetty.websocket" name="websocket-api" version="9.3.6.v20151106">
<artifact name="websocket-api-9.3.6.v20151106.jar">
<sha256 value="541a2c575082b6eec72a2ac59d7397301c41991978768b6b5c9d261ec9a25755"
origin="Generated by Gradle"/>
</artifact>
<artifact name="websocket-api-9.3.6.v20151106.pom">
<sha256 value="0626548a896902b77ababde8822793079556b292987c289024c46bf0cda70aae"
origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.eclipse.jetty.websocket" name="websocket-client" version="9.3.6.v20151106">
<artifact name="websocket-client-9.3.6.v20151106.jar">
<sha256 value="c4e74f5b2b9ec4b71ecc5c852039f5f43101d0b7332b9c95924591c633427518"
origin="Generated by Gradle"/>
</artifact>
<artifact name="websocket-client-9.3.6.v20151106.pom">
<sha256 value="331955c08e8219cab644221f10de1b1999a27b8fcaca016209873743f238900f"
origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.eclipse.jetty.websocket" name="websocket-common" version="9.3.6.v20151106">
<artifact name="websocket-common-9.3.6.v20151106.jar">
<sha256 value="df209f43c7d4485263088d1947e9ef20b450218b1c520c14654dcf25b0bd0793"
origin="Generated by Gradle"/>
</artifact>
<artifact name="websocket-common-9.3.6.v20151106.pom">
<sha256 value="a1ef4eb749ef73795a10ea6a9db98802c3d4e68b4089563e803a23ba54e79fee"
origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.eclipse.jetty.websocket" name="websocket-parent" version="9.3.6.v20151106">
<artifact name="websocket-parent-9.3.6.v20151106.pom">
<sha256 value="60cb05f669bcc0fddbdfa4479f8aa84b6a6479139ef9cec9dcd56686cb09f39b"
origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.eclipse.jetty.websocket" name="websocket-server" version="9.3.6.v20151106">
<artifact name="websocket-server-9.3.6.v20151106.jar">
<sha256 value="cfe658a601eff23ee151c03672ad838388365f79d98556a04be130ac7c11cf4d"
origin="Generated by Gradle"/>
</artifact>
<artifact name="websocket-server-9.3.6.v20151106.pom">
<sha256 value="f21c663407fc22327bf1633c5fd0dd6cda71806734a72c08b9ad6800a41c352b"
origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.eclipse.jetty.websocket" name="websocket-servlet" version="9.3.6.v20151106">
<artifact name="websocket-servlet-9.3.6.v20151106.jar">
<sha256 value="fa8d1146605c66b732d5c03066800fee63e4822cde688d189db4a336a442f412"
origin="Generated by Gradle"/>
</artifact>
<artifact name="websocket-servlet-9.3.6.v20151106.pom">
<sha256 value="b2f19e3f5d3c0e225b9d2acd375afab8dca1ad2b8faab54c68789da7e0308abf"
origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.fxmisc.easybind" name="easybind" version="1.0.3">
<artifact name="easybind-1.0.3.jar">

57
inventory/build.gradle Normal file
View File

@ -0,0 +1,57 @@
plugins {
id 'bisq.application'
id 'bisq.gradle.app_start_plugin.AppStartPlugin'
}
mainClassName = 'bisq.inventory.InventoryMonitorMain'
distTar.enabled = true
dependencies {
implementation project(':proto')
implementation project(':common')
implementation project(':p2p')
implementation project(':core')
annotationProcessor libs.lombok
compileOnly libs.javax.annotation
compileOnly libs.lombok
implementation libs.logback.classic
implementation libs.logback.core
implementation libs.google.gson
implementation libs.google.guava
implementation libs.protobuf.java
implementation libs.apache.commons.lang3
implementation libs.jetbrains.annotations
implementation libs.slf4j.api
implementation(libs.bitcoinj) {
exclude(module: 'bcprov-jdk15on')
exclude(module: 'guava')
exclude(module: 'jsr305')
exclude(module: 'okhttp')
exclude(module: 'okio')
exclude(module: 'protobuf-java')
exclude(module: 'slf4j-api')
}
implementation libs.spark.core
implementation libs.pushy
implementation libs.commons.codec
implementation libs.grpc.auth
implementation(libs.google.guice) {
exclude(module: 'guava')
}
implementation(libs.grpc.protobuf) {
exclude(module: 'animal-sniffer-annotations')
exclude(module: 'guava')
}
implementation(libs.grpc.stub) {
exclude(module: 'animal-sniffer-annotations')
exclude(module: 'guava')
}
runtimeOnly(libs.grpc.netty.shaded) {
exclude(module: 'animal-sniffer-annotations')
exclude(module: 'guava')
}
testAnnotationProcessor libs.lombok
testCompileOnly libs.lombok
}

View File

@ -0,0 +1,291 @@
/*
* This file is part of Bisq.
*
* Bisq is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bisq is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bisq. If not, see <http://www.gnu.org/licenses/>.
*/
package bisq.inventory;
import bisq.core.app.TorSetup;
import bisq.core.network.p2p.inventory.GetInventoryRequestManager;
import bisq.core.network.p2p.inventory.model.Average;
import bisq.core.network.p2p.inventory.model.DeviationSeverity;
import bisq.core.network.p2p.inventory.model.InventoryItem;
import bisq.core.network.p2p.inventory.model.RequestInfo;
import bisq.core.network.p2p.seed.DefaultSeedNodeRepository;
import bisq.core.proto.network.CoreNetworkProtoResolver;
import bisq.core.util.JsonUtil;
import bisq.network.p2p.NetworkNodeProvider;
import bisq.network.p2p.NodeAddress;
import bisq.network.p2p.network.NetworkNode;
import bisq.network.p2p.network.SetupListener;
import bisq.common.UserThread;
import bisq.common.config.BaseCurrencyNetwork;
import bisq.common.file.JsonFileManager;
import bisq.common.util.Tuple2;
import java.time.Clock;
import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.Nullable;
@Slf4j
public class InventoryMonitor implements SetupListener {
private final Map<NodeAddress, JsonFileManager> jsonFileManagerByNodeAddress = new HashMap<>();
private final Map<NodeAddress, List<RequestInfo>> requestInfoListByNode = new HashMap<>();
private final File appDir;
private final boolean useLocalhostForP2P;
private final int intervalSec;
private NetworkNode networkNode;
private GetInventoryRequestManager getInventoryRequestManager;
private ArrayList<NodeAddress> seedNodes;
private InventoryWebServer inventoryWebServer;
private int requestCounter = 0;
///////////////////////////////////////////////////////////////////////////////////////////
// Constructor
///////////////////////////////////////////////////////////////////////////////////////////
public InventoryMonitor(File appDir,
boolean useLocalhostForP2P,
BaseCurrencyNetwork network,
int intervalSec,
int port,
boolean cleanupTorFiles) {
this.appDir = appDir;
this.useLocalhostForP2P = useLocalhostForP2P;
this.intervalSec = intervalSec;
// We get more connectivity issues. Cleaning tor cache files helps usually for those problems.
File torDir = new File(appDir, "tor");
if (!torDir.exists()) {
torDir.mkdir();
}
TorSetup torSetup = new TorSetup(torDir);
if (cleanupTorFiles) {
torSetup.cleanupTorFiles(() -> initialize(network, port, torDir), log::error);
} else {
initialize(network, port, torDir);
}
}
private void initialize(BaseCurrencyNetwork network, int port, File torDir) {
networkNode = getNetworkNode(torDir);
getInventoryRequestManager = new GetInventoryRequestManager(networkNode);
// We maintain our own list as we want to monitor also old v2 nodes which are not part of the normal seed
// node list anymore.
String networkName = network.name().toLowerCase();
String fileName = network.isMainnet() ? "inv_" + networkName : networkName;
DefaultSeedNodeRepository.readSeedNodePropertyFile(fileName)
.ifPresent(bufferedReader -> {
seedNodes = new ArrayList<>(DefaultSeedNodeRepository.getSeedNodeAddressesFromPropertyFile(fileName));
addJsonFileManagers(seedNodes);
inventoryWebServer = new InventoryWebServer(port, seedNodes, bufferedReader);
networkNode.start(this);
});
}
///////////////////////////////////////////////////////////////////////////////////////////
// API
///////////////////////////////////////////////////////////////////////////////////////////
public void shutDown(Runnable shutDownCompleteHandler) {
networkNode.shutDown(shutDownCompleteHandler);
jsonFileManagerByNodeAddress.values().forEach(JsonFileManager::shutDown);
inventoryWebServer.shutDown();
}
///////////////////////////////////////////////////////////////////////////////////////////
// SetupListener
///////////////////////////////////////////////////////////////////////////////////////////
@Override
public void onTorNodeReady() {
UserThread.runPeriodically(this::requestFromAllSeeds, intervalSec);
requestFromAllSeeds();
}
@Override
public void onHiddenServicePublished() {
}
@Override
public void onSetupFailed(Throwable throwable) {
}
@Override
public void onRequestCustomBridges() {
}
///////////////////////////////////////////////////////////////////////////////////////////
// Private
///////////////////////////////////////////////////////////////////////////////////////////
private void requestFromAllSeeds() {
requestCounter++;
seedNodes.forEach(nodeAddress -> {
RequestInfo requestInfo = new RequestInfo(System.currentTimeMillis());
new Thread(() -> {
Thread.currentThread().setName("request @ " + getShortAddress(nodeAddress, useLocalhostForP2P));
getInventoryRequestManager.request(nodeAddress,
result -> processResponse(nodeAddress, requestInfo, result, null),
errorMessage -> processResponse(nodeAddress, requestInfo, null, errorMessage));
}).start();
});
}
private void processResponse(NodeAddress nodeAddress,
RequestInfo requestInfo,
@Nullable Map<InventoryItem, String> result,
@Nullable String errorMessage) {
if (errorMessage != null && !errorMessage.isEmpty()) {
log.warn("Error at connection to peer {}: {}", nodeAddress, errorMessage);
requestInfo.setErrorMessage(errorMessage);
} else {
requestInfo.setResponseTime(System.currentTimeMillis());
}
boolean ignoreDeviationAtStartup;
if (result != null) {
log.info("nodeAddress={}, result={}", nodeAddress, result.toString());
// If seed just started up we ignore the deviation as it can be expected that seed is still syncing
// DAO state/blocks. P2P data should be ready but as we received it from other seeds it is not that
// valuable information either, so we apply the ignore to all data.
if (result.containsKey(InventoryItem.jvmStartTime)) {
String jvmStartTimeString = result.get(InventoryItem.jvmStartTime);
long jvmStartTime = Long.parseLong(jvmStartTimeString);
ignoreDeviationAtStartup = jvmStartTime < TimeUnit.MINUTES.toMillis(2);
} else {
ignoreDeviationAtStartup = false;
}
} else {
ignoreDeviationAtStartup = false;
}
requestInfoListByNode.putIfAbsent(nodeAddress, new ArrayList<>());
List<RequestInfo> requestInfoList = requestInfoListByNode.get(nodeAddress);
// We create average of all nodes latest results. It might be that the nodes last result is
// from a previous request as the response has not arrived yet.
//TODO might be not a good idea to use the last result if its not a recent one. a faulty node would distort
// the average calculation.
// As we add at the end our own result the average is excluding our own value
Collection<List<RequestInfo>> requestInfoListByNodeValues = requestInfoListByNode.values();
Set<RequestInfo> requestInfoSet = requestInfoListByNodeValues.stream()
.filter(list -> !list.isEmpty())
.map(list -> list.get(list.size() - 1))
.collect(Collectors.toSet());
Map<InventoryItem, Double> averageValues = Average.of(requestInfoSet);
String daoStateChainHeight = result != null &&
result.containsKey(InventoryItem.daoStateChainHeight) ?
result.get(InventoryItem.daoStateChainHeight) :
null;
List.of(InventoryItem.values()).forEach(inventoryItem -> {
String value = result != null ? result.get(inventoryItem) : null;
Tuple2<Double, Double> tuple = inventoryItem.getDeviationAndAverage(averageValues, value);
Double deviation = tuple != null ? tuple.first : null;
Double average = tuple != null ? tuple.second : null;
DeviationSeverity deviationSeverity = ignoreDeviationAtStartup ? DeviationSeverity.IGNORED :
inventoryItem.getDeviationSeverity(deviation,
requestInfoListByNodeValues,
value,
daoStateChainHeight);
int endIndex = Math.max(0, requestInfoList.size() - 1);
int deviationTolerance = inventoryItem.getDeviationTolerance();
int fromIndex = Math.max(0, endIndex - deviationTolerance);
List<DeviationSeverity> lastDeviationSeverityEntries = requestInfoList.subList(fromIndex, endIndex).stream()
.filter(e -> e.getDataMap().containsKey(inventoryItem))
.map(e -> e.getDataMap().get(inventoryItem).getDeviationSeverity())
.collect(Collectors.toList());
long numWarnings = lastDeviationSeverityEntries.stream()
.filter(e -> e == DeviationSeverity.WARN)
.count();
long numAlerts = lastDeviationSeverityEntries.stream()
.filter(e -> e == DeviationSeverity.ALERT)
.count();
boolean persistentWarning = numWarnings == deviationTolerance;
boolean persistentAlert = numAlerts == deviationTolerance;
RequestInfo.Data data = new RequestInfo.Data(value, average, deviation, deviationSeverity, persistentWarning, persistentAlert);
requestInfo.getDataMap().put(inventoryItem, data);
});
requestInfoList.add(requestInfo);
inventoryWebServer.onNewRequestInfo(requestInfoListByNode, requestCounter);
String json = JsonUtil.objectToJson(requestInfo);
jsonFileManagerByNodeAddress.get(nodeAddress).writeToDisc(json, String.valueOf(requestInfo.getRequestStartTime()));
}
private void addJsonFileManagers(List<NodeAddress> seedNodes) {
File jsonDir = new File(appDir, "json");
if (!jsonDir.exists() && !jsonDir.mkdir()) {
log.warn("make jsonDir failed");
}
seedNodes.forEach(nodeAddress -> {
JsonFileManager jsonFileManager = new JsonFileManager(new File(jsonDir, getShortAddress(nodeAddress, useLocalhostForP2P)));
jsonFileManagerByNodeAddress.put(nodeAddress, jsonFileManager);
});
}
private NetworkNode getNetworkNode(File torDir) {
CoreNetworkProtoResolver networkProtoResolver = new CoreNetworkProtoResolver(Clock.systemDefaultZone());
return new NetworkNodeProvider(networkProtoResolver,
() -> null,
null,
12,
useLocalhostForP2P,
9999,
torDir,
null,
"",
"",
-1,
"",
null,
false,
false)
.get();
}
private String getShortAddress(NodeAddress nodeAddress, boolean useLocalhostForP2P) {
return useLocalhostForP2P ?
nodeAddress.getFullAddress().replace(":", "_") :
nodeAddress.getFullAddress().substring(0, 10);
}
}

View File

@ -0,0 +1,135 @@
/*
* This file is part of Bisq.
*
* Bisq is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bisq is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bisq. If not, see <http://www.gnu.org/licenses/>.
*/
package bisq.inventory;
import bisq.core.locale.Res;
import bisq.common.UserThread;
import bisq.common.app.AsciiLogo;
import bisq.common.app.Log;
import bisq.common.app.Version;
import bisq.common.config.BaseCurrencyNetwork;
import bisq.common.util.Utilities;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import java.nio.file.Paths;
import java.io.File;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import ch.qos.logback.classic.Level;
import lombok.extern.slf4j.Slf4j;
import sun.misc.Signal;
@Slf4j
public class InventoryMonitorMain {
private static InventoryMonitor inventoryMonitor;
private static boolean stopped;
// prog args for regtest: 10 1 BTC_REGTEST
public static void main(String[] args) {
// Default values
int intervalSec = 120;
boolean useLocalhostForP2P = false;
BaseCurrencyNetwork network = BaseCurrencyNetwork.BTC_MAINNET;
int port = 8080;
if (args.length > 0) {
intervalSec = Integer.parseInt(args[0]);
}
if (args.length > 1) {
useLocalhostForP2P = args[1].equals("1");
}
if (args.length > 2) {
network = BaseCurrencyNetwork.valueOf(args[2]);
}
if (args.length > 3) {
port = Integer.parseInt(args[3]);
}
// todo
boolean cleanupTorFiles = false;
String appName = "bisq-inventory-monitor-" + network;
File appDir = new File(Utilities.getUserDataDir(), appName);
if (!appDir.exists() && !appDir.mkdir()) {
log.warn("make appDir failed");
}
inventoryMonitor = new InventoryMonitor(appDir, useLocalhostForP2P, network, intervalSec, port, cleanupTorFiles);
setup(network, appDir);
// We shutdown after 5 days to avoid potential memory leak issue.
// The start script will restart the app.
UserThread.runAfter(InventoryMonitorMain::shutDown, TimeUnit.DAYS.toSeconds(5));
}
private static void setup(BaseCurrencyNetwork network, File appDir) {
String logPath = Paths.get(appDir.getPath(), "bisq").toString();
Log.setup(logPath);
Log.setLevel(Level.INFO);
AsciiLogo.showAsciiLogo();
Version.setBaseCryptoNetworkId(network.ordinal());
Res.setup(); // Used for some formatting in the webserver
// We do not set any capabilities as we don't want to receive any network data beside our response.
// We also do not use capabilities for the request/response messages as we only connect to seeds nodes and
ThreadFactory threadFactory = new ThreadFactoryBuilder()
.setNameFormat(inventoryMonitor.getClass().getSimpleName())
.setDaemon(true)
.build();
UserThread.setExecutor(Executors.newSingleThreadExecutor(threadFactory));
Signal.handle(new Signal("INT"), signal -> {
UserThread.execute(InventoryMonitorMain::shutDown);
});
Signal.handle(new Signal("TERM"), signal -> {
UserThread.execute(InventoryMonitorMain::shutDown);
});
keepRunning();
}
private static void shutDown() {
stopped = true;
inventoryMonitor.shutDown(() -> {
System.exit(0);
});
}
private static void keepRunning() {
while (!stopped) {
try {
Thread.sleep(Long.MAX_VALUE);
} catch (InterruptedException ignore) {
}
}
}
}

View File

@ -0,0 +1,552 @@
/*
* This file is part of Bisq.
*
* Bisq is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bisq is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bisq. If not, see <http://www.gnu.org/licenses/>.
*/
package bisq.inventory;
import bisq.core.network.p2p.inventory.model.DeviationByIntegerDiff;
import bisq.core.network.p2p.inventory.model.DeviationByPercentage;
import bisq.core.network.p2p.inventory.model.DeviationSeverity;
import bisq.core.network.p2p.inventory.model.InventoryItem;
import bisq.core.network.p2p.inventory.model.RequestInfo;
import bisq.core.util.FormattingUtils;
import bisq.network.p2p.NodeAddress;
import bisq.common.app.Version;
import bisq.common.util.MathUtils;
import bisq.common.util.Utilities;
import com.google.common.base.Joiner;
import java.io.BufferedReader;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.Nullable;
import spark.Spark;
@Slf4j
public class InventoryWebServer {
private final static String CLOSE_TAG = "</font><br/>";
private final static String WARNING_ICON = "&#9888; ";
private final static String ALERT_ICON = "&#9760; "; // &#9889; &#9889;
private final List<NodeAddress> seedNodes;
private final Map<String, String> operatorByNodeAddress = new HashMap<>();
private String html;
private int requestCounter;
///////////////////////////////////////////////////////////////////////////////////////////
// Constructor
///////////////////////////////////////////////////////////////////////////////////////////
public InventoryWebServer(int port,
List<NodeAddress> seedNodes,
BufferedReader seedNodeFile) {
this.seedNodes = seedNodes;
setupOperatorMap(seedNodeFile);
Spark.port(port);
Spark.get("/", (req, res) -> {
log.info("Incoming request from: {}", req.userAgent());
return html == null ? "Starting up..." : html;
});
}
///////////////////////////////////////////////////////////////////////////////////////////
// API
///////////////////////////////////////////////////////////////////////////////////////////
public void onNewRequestInfo(Map<NodeAddress, List<RequestInfo>> requestInfoListByNode, int requestCounter) {
this.requestCounter = requestCounter;
html = generateHtml(requestInfoListByNode);
}
public void shutDown() {
Spark.stop();
}
///////////////////////////////////////////////////////////////////////////////////////////
// HTML
///////////////////////////////////////////////////////////////////////////////////////////
private String generateHtml(Map<NodeAddress, List<RequestInfo>> map) {
StringBuilder html = new StringBuilder();
html.append("<html>" +
"<head>" +
"<style type=\"text/css\">" +
" a {" +
" text-decoration:none; color: black;" +
" }" +
" #warn { color: #ff7700; } " +
" #alert { color: #ff0000; } " +
"table, th, td {border: 1px solid black;}" +
"</style></head>" +
"<body><h3>")
.append("Current time: ").append(new Date().toString()).append("<br/>")
.append("Request cycle: ").append(requestCounter).append("<br/>")
.append("Version/commit: ").append(Version.VERSION).append(" / ").append("TODO RequestInfo.COMMIT_HASH").append("<br/>")
.append("<table style=\"width:100%\">")
.append("<tr>")
.append("<th align=\"left\">Seed node info</th>")
.append("<th align=\"left\">Request info</th>")
.append("<th align=\"left\">Data inventory</th>")
.append("<th align=\"left\">DAO data</th>")
.append("<th align=\"left\">Network info</th>").append("</tr>");
seedNodes.forEach(seedNode -> {
html.append("<tr valign=\"top\">");
if (map.containsKey(seedNode) && !map.get(seedNode).isEmpty()) {
List<RequestInfo> list = map.get(seedNode);
int numRequests = list.size();
RequestInfo requestInfo = list.get(numRequests - 1);
html.append("<td>").append(getSeedNodeInfo(seedNode, requestInfo)).append("</td>")
.append("<td>").append(getRequestInfo(seedNode, requestInfo, numRequests, map)).append("</td>")
.append("<td>").append(getDataInfo(seedNode, requestInfo, map)).append("</td>")
.append("<td>").append(getDaoInfo(seedNode, requestInfo, map)).append("</td>")
.append("<td>").append(getNetworkInfo(seedNode, requestInfo, map)).append("</td>");
} else {
html.append("<td>").append(getSeedNodeInfo(seedNode, null)).append("</td>")
.append("<td>").append("n/a").append("</td>")
.append("<td>").append("n/a").append("</td>")
.append("<td>").append("n/a").append("</td>")
.append("<td>").append("n/a").append("</td>");
}
html.append("</tr>");
});
html.append("</table></body></html>");
return html.toString();
}
///////////////////////////////////////////////////////////////////////////////////////////
// Sub sections
///////////////////////////////////////////////////////////////////////////////////////////
private String getSeedNodeInfo(NodeAddress nodeAddress,
@Nullable RequestInfo requestInfo) {
StringBuilder sb = new StringBuilder();
String operator = operatorByNodeAddress.get(nodeAddress.getFullAddress());
sb.append("Operator: ").append(operator).append("<br/>");
String address = nodeAddress.getFullAddress();
String filteredSeeds = requestInfo != null ? requestInfo.getValue(InventoryItem.filteredSeeds) : null;
if (filteredSeeds != null && filteredSeeds.contains(address)) {
sb.append(getColorTagByDeviationSeverity(DeviationSeverity.ALERT)).append("Node address: ")
.append(address).append(" (is filtered!)").append(CLOSE_TAG);
} else {
sb.append("Node address: ").append(address).append("<br/>");
}
if (requestInfo != null) {
sb.append("Version: ").append(requestInfo.getDisplayValue(InventoryItem.version)).append("<br/>");
sb.append("Commit hash: ").append(requestInfo.getDisplayValue(InventoryItem.commitHash)).append("<br/>");
String memory = requestInfo.getValue(InventoryItem.usedMemory);
String memoryString = memory != null ? Utilities.readableFileSize(Long.parseLong(memory)) : "n/a";
sb.append("Memory used: ")
.append(memoryString)
.append("<br/>");
String jvmStartTimeString = requestInfo.getValue(InventoryItem.jvmStartTime);
long jvmStartTime = jvmStartTimeString != null ? Long.parseLong(jvmStartTimeString) : 0;
sb.append("Node started at: ")
.append(new Date(jvmStartTime).toString())
.append("<br/>");
String duration = jvmStartTime > 0 ?
FormattingUtils.formatDurationAsWords(System.currentTimeMillis() - jvmStartTime,
true, true) :
"n/a";
sb.append("Run duration: ").append(duration).append("<br/>");
String filteredSeedNodes = requestInfo.getDisplayValue(InventoryItem.filteredSeeds)
.replace(System.getProperty("line.separator"), "<br/>");
if (filteredSeedNodes.isEmpty()) {
filteredSeedNodes = "-";
}
sb.append("Filtered seed nodes: ")
.append(filteredSeedNodes)
.append("<br/>");
}
return sb.toString();
}
private String getRequestInfo(NodeAddress seedNode,
RequestInfo requestInfo,
int numRequests,
Map<NodeAddress, List<RequestInfo>> map) {
StringBuilder sb = new StringBuilder();
DeviationSeverity deviationSeverity = numRequests == requestCounter ?
DeviationSeverity.OK :
requestCounter - numRequests > 4 ?
DeviationSeverity.ALERT :
DeviationSeverity.WARN;
sb.append("Number of requests: ").append(getColorTagByDeviationSeverity(deviationSeverity))
.append(numRequests).append(CLOSE_TAG);
DeviationSeverity rrtDeviationSeverity = DeviationSeverity.OK;
String rrtString = "n/a";
if (requestInfo.getResponseTime() > 0) {
long rrt = requestInfo.getResponseTime() - requestInfo.getRequestStartTime();
if (rrt > 20_000) {
rrtDeviationSeverity = DeviationSeverity.ALERT;
} else if (rrt > 10_000) {
rrtDeviationSeverity = DeviationSeverity.WARN;
}
rrtString = MathUtils.roundDouble(rrt / 1000d, 3) + " sec";
}
sb.append("Round trip time: ").append(getColorTagByDeviationSeverity(rrtDeviationSeverity))
.append(rrtString).append(CLOSE_TAG);
Date requestStartTime = new Date(requestInfo.getRequestStartTime());
sb.append("Requested at: ").append(requestStartTime).append("<br/>");
String responseTime = requestInfo.getResponseTime() > 0 ?
new Date(requestInfo.getResponseTime()).toString() :
"n/a";
sb.append("Response received at: ").append(responseTime).append("<br/>");
sb.append(getErrorMsgLine(seedNode, requestInfo, map));
sb.append(getLastSuccessfulResponseLine(seedNode, map));
return sb.toString();
}
private String getDataInfo(NodeAddress seedNode,
RequestInfo requestInfo,
Map<NodeAddress, List<RequestInfo>> map) {
StringBuilder sb = new StringBuilder();
sb.append(getLine(InventoryItem.OfferPayload, seedNode, requestInfo, map));
sb.append(getLine(InventoryItem.MailboxStoragePayload, seedNode, requestInfo, map));
sb.append(getLine(InventoryItem.TradeStatistics3, seedNode, requestInfo, map));
sb.append(getLine(InventoryItem.AccountAgeWitness, seedNode, requestInfo, map));
sb.append(getLine(InventoryItem.SignedWitness, seedNode, requestInfo, map));
sb.append(getLine(InventoryItem.Alert, seedNode, requestInfo, map));
sb.append(getLine(InventoryItem.Filter, seedNode, requestInfo, map));
sb.append(getLine(InventoryItem.Mediator, seedNode, requestInfo, map));
sb.append(getLine(InventoryItem.RefundAgent, seedNode, requestInfo, map));
return sb.toString();
}
private String getDaoInfo(NodeAddress seedNode,
RequestInfo requestInfo,
Map<NodeAddress, List<RequestInfo>> map) {
StringBuilder sb = new StringBuilder();
sb.append(getLine("Number of BSQ blocks: ", InventoryItem.numBsqBlocks, seedNode, requestInfo, map));
sb.append(getLine(InventoryItem.TempProposalPayload, seedNode, requestInfo, map));
sb.append(getLine(InventoryItem.ProposalPayload, seedNode, requestInfo, map));
sb.append(getLine(InventoryItem.BlindVotePayload, seedNode, requestInfo, map));
sb.append(getLine("DAO state block height: ", InventoryItem.daoStateChainHeight, seedNode, requestInfo, map));
sb.append(getLine("DAO state hash: ", InventoryItem.daoStateHash, seedNode, requestInfo, map));
// The hash for proposal changes only at first block of blind vote phase but as we do not want to initialize the
// dao domain we cannot check that. But we also don't need that as we can just compare that all hashes at all
// blocks from all seeds are the same. Same for blindVoteHash.
sb.append(getLine("Proposal state hash: ", InventoryItem.proposalHash, seedNode, requestInfo, map));
sb.append(getLine("Blind vote state hash: ", InventoryItem.blindVoteHash, seedNode, requestInfo, map));
return sb.toString();
}
private String getNetworkInfo(NodeAddress seedNode,
RequestInfo requestInfo,
Map<NodeAddress, List<RequestInfo>> map) {
StringBuilder sb = new StringBuilder();
sb.append(getLine("Max. connections: ",
InventoryItem.maxConnections, seedNode, requestInfo, map));
sb.append(getLine("Number of connections: ",
InventoryItem.numConnections, seedNode, requestInfo, map));
sb.append(getLine("Peak number of connections: ",
InventoryItem.peakNumConnections, seedNode, requestInfo, map));
sb.append(getLine("Number of 'All connections lost' events: ",
InventoryItem.numAllConnectionsLostEvents, seedNode, requestInfo, map));
sb.append(getLine("Sent messages/sec: ",
InventoryItem.sentMessagesPerSec, seedNode, requestInfo, map, this::getRounded));
sb.append(getLine("Received messages/sec: ",
InventoryItem.receivedMessagesPerSec, seedNode, requestInfo, map, this::getRounded));
sb.append(getLine("Sent kB/sec: ",
InventoryItem.sentBytesPerSec, seedNode, requestInfo, map, this::getKbRounded));
sb.append(getLine("Received kB/sec: ",
InventoryItem.receivedBytesPerSec, seedNode, requestInfo, map, this::getKbRounded));
sb.append(getLine("Sent data: ",
InventoryItem.sentBytes, seedNode, requestInfo, map,
value -> Utilities.readableFileSize(Long.parseLong(value))));
sb.append(getLine("Received data: ",
InventoryItem.receivedBytes, seedNode, requestInfo, map,
value -> Utilities.readableFileSize(Long.parseLong(value))));
return sb.toString();
}
///////////////////////////////////////////////////////////////////////////////////////////
// Utils
///////////////////////////////////////////////////////////////////////////////////////////
private String getLine(InventoryItem inventoryItem,
NodeAddress seedNode,
RequestInfo requestInfo,
Map<NodeAddress, List<RequestInfo>> map) {
return getLine(getTitle(inventoryItem),
inventoryItem,
seedNode,
requestInfo,
map);
}
private String getLine(String title,
InventoryItem inventoryItem,
NodeAddress seedNode,
RequestInfo requestInfo,
Map<NodeAddress, List<RequestInfo>> map) {
return getLine(title,
inventoryItem,
seedNode,
requestInfo,
map,
null);
}
private String getLine(String title,
InventoryItem inventoryItem,
NodeAddress seedNode,
RequestInfo requestInfo,
Map<NodeAddress, List<RequestInfo>> map,
@Nullable Function<String, String> formatter) {
String displayValue = requestInfo.getDisplayValue(inventoryItem);
String value = requestInfo.getValue(inventoryItem);
if (formatter != null && value != null) {
displayValue = formatter.apply(value);
}
String deviationAsPercentString = "";
DeviationSeverity deviationSeverity = DeviationSeverity.OK;
if (requestInfo.getDataMap().containsKey(inventoryItem)) {
RequestInfo.Data data = requestInfo.getDataMap().get(inventoryItem);
deviationAsPercentString = getDeviationAsPercentString(inventoryItem, data);
deviationSeverity = data.getDeviationSeverity();
}
List<RequestInfo> requestInfoList = map.get(seedNode);
String historicalWarnings = "";
String historicalAlerts = "";
List<String> warningsAtRequestNumber = new ArrayList<>();
List<String> alertsAtRequestNumber = new ArrayList<>();
if (requestInfoList != null) {
for (int i = 0; i < requestInfoList.size(); i++) {
RequestInfo reqInfo = requestInfoList.get(i);
Map<InventoryItem, RequestInfo.Data> deviationInfoMap = reqInfo.getDataMap();
if (deviationInfoMap.containsKey(inventoryItem)) {
RequestInfo.Data data = deviationInfoMap.get(inventoryItem);
String deviationAsPercent = getDeviationAsPercentString(inventoryItem, data);
if (data.isPersistentWarning()) {
warningsAtRequestNumber.add((i + 1) + deviationAsPercent);
} else if (data.isPersistentAlert()) {
alertsAtRequestNumber.add((i + 1) + deviationAsPercent);
}
}
}
if (!warningsAtRequestNumber.isEmpty()) {
historicalWarnings = warningsAtRequestNumber.size() + " repeated warning(s) at request(s) " +
Joiner.on(", ").join(warningsAtRequestNumber);
}
if (!alertsAtRequestNumber.isEmpty()) {
historicalAlerts = alertsAtRequestNumber.size() + " repeated alert(s) at request(s): " +
Joiner.on(", ").join(alertsAtRequestNumber);
}
}
String historicalWarningsHtml = warningsAtRequestNumber.isEmpty() ? "" :
", <b><a id=\"warn\" href=\"#\" title=\"" + historicalWarnings + "\">" + WARNING_ICON +
warningsAtRequestNumber.size() + "</a></b>";
String historicalAlertsHtml = alertsAtRequestNumber.isEmpty() ? "" :
", <b><a id=\"alert\" href=\"#\" title=\"" + historicalAlerts + "\">" + ALERT_ICON +
alertsAtRequestNumber.size() + "</a></b>";
return title +
getColorTagByDeviationSeverity(deviationSeverity) +
displayValue +
deviationAsPercentString +
historicalWarningsHtml +
historicalAlertsHtml +
CLOSE_TAG;
}
private String getDeviationAsPercentString(InventoryItem inventoryItem, RequestInfo.Data data) {
Double deviation = data.getDeviation();
if (deviation == null || deviation == 1) {
return "";
}
if (inventoryItem.getDeviationType() instanceof DeviationByPercentage) {
return getDeviationInRoundedPercent(deviation);
} else if (inventoryItem.getDeviationType() instanceof DeviationByIntegerDiff) {
// For larger numbers like chain height we need to show all decimals as diff can be very small
return getDeviationInExactPercent(deviation);
} else {
return "";
}
}
private String getDeviationInRoundedPercent(double deviation) {
return " (" + MathUtils.roundDouble(100 * deviation, 2) + " %)";
}
private String getDeviationInExactPercent(double deviation) {
return " (" + 100 * deviation + " %)";
}
private String getColorTagByDeviationSeverity(@Nullable DeviationSeverity deviationSeverity) {
if (deviationSeverity == null) {
return "<font color=\"black\">";
}
switch (deviationSeverity) {
case WARN:
return "<font color=\"#0000cc\">";
case ALERT:
return "<font color=\"#cc0000\">";
case IGNORED:
return "<font color=\"#333333\">";
case OK:
default:
return "<font color=\"black\">";
}
}
private String getTitle(InventoryItem inventoryItem) {
return "Number of " + inventoryItem.getKey() + ": ";
}
private String getRounded(String value) {
return String.valueOf(MathUtils.roundDouble(Double.parseDouble(value), 2));
}
private String getKbRounded(String bytes) {
return String.valueOf(MathUtils.roundDouble(Double.parseDouble(bytes) / 1000, 2));
}
private void setupOperatorMap(BufferedReader seedNodeFile) {
seedNodeFile.lines().forEach(line -> {
if (!line.startsWith("#")) {
String[] strings = line.split(" \\(@");
String node = strings.length > 0 ? strings[0] : "n/a";
String operator = strings.length > 1 ? strings[1].replace(")", "") : "n/a";
operatorByNodeAddress.put(node, operator);
}
});
}
// We use here a bit diff. model as with other historical data alerts/warnings as we do not store it in the data
// object as we do with normal inventoryItems. So the historical error msg are not available in the json file.
// If we need it we have to move that handling here to the InventoryMonitor and change the data model to support the
// missing data for error messages.
private String getErrorMsgLine(NodeAddress seedNode,
RequestInfo requestInfo,
Map<NodeAddress, List<RequestInfo>> map) {
String errorMessage = requestInfo.hasError() ? requestInfo.getErrorMessage() : "-";
List<RequestInfo> requestInfoList = map.get(seedNode);
List<String> errorsAtRequestNumber = new ArrayList<>();
String historicalErrorsHtml = "";
if (requestInfoList != null) {
for (int i = 0; i < requestInfoList.size(); i++) {
RequestInfo requestInfo1 = requestInfoList.get(i);
// We ignore old errors as at startup timeouts are expected and each node restarts once a day
long duration = System.currentTimeMillis() - requestInfo1.getRequestStartTime();
if (requestInfo1.getRequestStartTime() > 0 && duration > TimeUnit.HOURS.toMillis(24)) {
continue;
}
if (requestInfo1.hasError()) {
errorsAtRequestNumber.add((i + 1) + " (" + requestInfo1.getErrorMessage() + ")");
}
}
if (!errorsAtRequestNumber.isEmpty()) {
String errorIcon;
String type;
String style;
if (errorsAtRequestNumber.size() > 4) {
errorIcon = ALERT_ICON;
type = "alert";
style = "alert";
} else {
errorIcon = WARNING_ICON;
type = "warning";
style = "warn";
}
String historicalAlerts = errorsAtRequestNumber.size() + " repeated " + type + "(s) at request(s): " +
Joiner.on(", ").join(errorsAtRequestNumber);
historicalErrorsHtml = errorsAtRequestNumber.isEmpty() ? "" :
", <b><a id=\"" + style + "\" href=\"#\" title=\"" + historicalAlerts + "\">" + errorIcon +
errorsAtRequestNumber.size() + "</a></b>";
}
}
DeviationSeverity deviationSeverity = requestInfo.hasError() ?
errorsAtRequestNumber.size() > 4 ? DeviationSeverity.ALERT : DeviationSeverity.WARN
: DeviationSeverity.OK;
return "Error message: " +
getColorTagByDeviationSeverity(deviationSeverity) +
errorMessage +
historicalErrorsHtml +
CLOSE_TAG;
}
private String getLastSuccessfulResponseLine(NodeAddress seedNode,
Map<NodeAddress, List<RequestInfo>> map) {
long newestResponseTime = 0;
List<RequestInfo> requestInfoList = map.get(seedNode);
if (requestInfoList != null) {
for (int i = 0; i < requestInfoList.size(); i++) {
RequestInfo requestInfo1 = requestInfoList.get(i);
newestResponseTime = Math.max(newestResponseTime, requestInfo1.getResponseTime());
}
}
String responseMessage = newestResponseTime > 0 ? new Date(newestResponseTime).toString() : "none";
return "Last response received: " +
responseMessage +
CLOSE_TAG;
}
}

View File

@ -0,0 +1,10 @@
# nodeaddress.onion:port [(@owner,@backup)]
devinv3rhon24gqf5v6ondoqgyrbzyqihzyouzv7ptltsewhfmox2zqd.onion:8000 (@devinbileck)
devinsn2teu33efff62bnvwbxmfgbfjlgqsu3ad4b4fudx3a725eqnyd.onion:8000 (@devinbileck)
devinsn3xuzxhj6pmammrxpydhwwmwp75qkksedo5dn2tlmu7jggo7id.onion:8000 (@devinbileck)
sn3emzy56u3mxzsr4geysc52feoq5qt7ja56km6gygwnszkshunn2sid.onion:8000 (@emzy)
sn4emzywye3dhjouv7jig677qepg7fnusjidw74fbwneieruhmi7fuyd.onion:8000 (@emzy)
sn5emzyvxuildv34n6jewfp2zeota4aq63fsl5yyilnvksezr3htveqd.onion:8000 (@emzy)
y6mvobc6tfp7l3rq2rae7hayvkmy35su33cun2mfdbzd4uw536pqtlyd.onion:8000 (@jester4042)
xaebw6lpcckkyb2anyzyfynthebek2abqzyhchenfrdqlfktezgtrtqd.onion:8000 (@jester4042)
33ol66i7crfrnypjlpd7kem3imo6zmjkvxdr6ipcdx3e2skbpcrfzuqd.onion:8000 (@jester4042)

View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="CONSOLE_APPENDER" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%highlight(%d{MMM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{40}: %msg %xEx%n)</pattern>
</encoder>
</appender>
<root level="TRACE">
<appender-ref ref="CONSOLE_APPENDER"/>
</root>
<!-- <logger name="org.bitcoinj" level="WARN"/>-->
<logger name="org.berndpruenster.netlayer.tor.Tor" level="WARN"/>
</configuration>

View File

@ -19,9 +19,6 @@ package bisq.network.p2p.network;
import java.util.List;
import org.jetbrains.annotations.Nullable;
public interface BridgeAddressProvider {
@Nullable
List<String> getBridgeAddresses();
}

View File

@ -27,6 +27,7 @@ include 'core'
include 'cli'
include 'daemon'
include 'desktop'
include 'inventory'
include 'persistence'
include 'seednode'
include 'statsnode'