From 5c02ce57669a7eee6e01143a686eeba782d65968 Mon Sep 17 00:00:00 2001 From: chimp1984 Date: Wed, 18 Sep 2019 18:39:37 +0200 Subject: [PATCH 01/14] Introduce gRPC API proof of concept This commit introduces a new `grpc` module including the following key types: - BisqGrpcServer: The API implementation itself, along with generated gRPC Response/Reploy types defined in grpc/src/main/proto/grpc.proto. - BisqGrpcServerMain: A 'headless' / daemon-like entry point for running a Bisq node without the JavaFX desktop UI. - BisqGrpcClient: A simple, repl-style client for the API that allows the user to exercise the various endpoints as seen in the example below. In the `desktop` module, the BisqAppMain class has been modified to start a BisqGrpcServer instance if the `--desktopWithGrpcApi` option has been set to `true`. In the `core` module, a new `CoreApi` class has been introduced providing a kind of comprehensive facade for all Bisq functionality to be exposed via the RPC API. How to explore the proof of concept: 1. Run the main() method in BisqAppMain providing `--desktopWithGrpcApi=true` as a program argument or alternatively, run the main() method in BisqGrpcServerMain, where no special option is required. In either case, you'll notice the following entry in the log output: INFO bisq.grpc.BisqGrpcServer: Server started, listening on 8888 2. Now run the main() method in BisqGrpcClient. Once it has started up you are connected to the gRPC server started in step 1 above. To exercise the API, type `getVersion` via stdin and hit return. You should see the following response: INFO bisq.grpc.BisqGrpcClient - 1.2.4 Likewise, you can type `getBalance` and you'll see the following response: INFO bisq.grpc.BisqGrpcClient - 0.00 BTC and so forth for each of the implemented endpoints. For a list of implemented endpoints, see BisqGrpcServer.start(). Note once again that the code here is merely a proof of concept and should not be considered complete or production-ready in any way. In a subsequent commit, the `--desktopWithGrpcApi` option will be disabled in order to avoid any potential production use. The content of this commit is the result of squashing a number of commits originally authored by chimp1984 in the `chimp1984` fork's `grpc` branch. Co-authored-by: Chris Beams --- build.gradle | 72 ++++- core/src/main/java/bisq/core/CoreApi.java | 163 ++++++++++ .../java/bisq/desktop/app/BisqAppMain.java | 18 +- gradle/witness/gradle-witness.gradle | 53 +++- grpc/src/main/java/bisq/grpc/BisqGrpcApp.java | 26 ++ .../main/java/bisq/grpc/BisqGrpcClient.java | 297 ++++++++++++++++++ .../main/java/bisq/grpc/BisqGrpcServer.java | 236 ++++++++++++++ .../java/bisq/grpc/BisqGrpcServerMain.java | 127 ++++++++ grpc/src/main/java/resources/logback.xml | 16 + grpc/src/main/proto/grpc.proto | 148 +++++++++ settings.gradle | 1 + 11 files changed, 1142 insertions(+), 15 deletions(-) create mode 100644 core/src/main/java/bisq/core/CoreApi.java create mode 100644 grpc/src/main/java/bisq/grpc/BisqGrpcApp.java create mode 100644 grpc/src/main/java/bisq/grpc/BisqGrpcClient.java create mode 100644 grpc/src/main/java/bisq/grpc/BisqGrpcServer.java create mode 100644 grpc/src/main/java/bisq/grpc/BisqGrpcServerMain.java create mode 100644 grpc/src/main/java/resources/logback.xml create mode 100644 grpc/src/main/proto/grpc.proto diff --git a/build.gradle b/build.gradle index 2e2341b2cee..dff1addf2f0 100644 --- a/build.gradle +++ b/build.gradle @@ -31,6 +31,7 @@ configure(subprojects) { bitcoinjVersion = 'a88d36d' btcdCli4jVersion = '975ff5d4' codecVersion = '1.9' + commonProtosVersion = '1.17.0' easybindVersion = '1.0.3' easyVersion = '4.0.1' findbugsVersion = '3.0.2' @@ -38,6 +39,7 @@ configure(subprojects) { fontawesomefxVersion = '8.0.0' fontawesomefxCommonsVersion = '9.1.2' fontawesomefxMaterialdesignfontVersion = '2.0.26-9.1.2' + grpcVersion = '1.25.0' guavaVersion = '20.0' guiceVersion = '4.2.2' hamcrestVersion = '1.3' @@ -58,6 +60,7 @@ configure(subprojects) { logbackVersion = '1.1.10' lombokVersion = '1.18.2' mockitoVersion = '3.0.0' + nettyTcNativeVersion = '2.0.27.Final' netlayerVersion = '0.6.5.2' protobufVersion = '3.9.1' pushyVersion = '0.13.2' @@ -91,7 +94,8 @@ configure([project(':desktop'), project(':relay'), project(':seednode'), project(':statsnode'), - project(':pricenode')]) { + project(':pricenode'), + project(':grpc')]) { apply plugin: 'application' @@ -267,7 +271,6 @@ configure(project(':core')) { } } - configure(project(':desktop')) { apply plugin: 'com.github.johnrengelman.shadow' apply plugin: 'witness' @@ -286,6 +289,7 @@ configure(project(':desktop')) { dependencies { compile project(':core') + compile project(':grpc') compile "net.glxn:qrgen:$qrgenVersion" compile "de.jensd:fontawesomefx:$fontawesomefxVersion" compile "de.jensd:fontawesomefx-commons:$fontawesomefxCommonsVersion" @@ -402,3 +406,67 @@ configure(project(':statsnode')) { annotationProcessor "org.projectlombok:lombok:$lombokVersion" } } + +configure(project(':grpc')) { + apply plugin: 'com.google.protobuf' + + mainClassName = 'bisq.grpc.BisqGrpcServerMain' + + // FIXME we dont want to have one src dir inside the other.... + sourceSets.main.java.srcDir "$buildDir/generated/source/proto/main" + sourceSets.main.java.srcDir "$buildDir/generated/source/proto/main/java" + + protobuf { + protoc { + artifact = "com.google.protobuf:protoc:$protobufVersion" + } + plugins { + grpc { + artifact = "io.grpc:protoc-gen-grpc-java:$grpcVersion" + } + } + generateProtoTasks { + all()*.plugins { + grpc {} + } + } + } + + dependencies { + compile project(':core') + compile "com.google.protobuf:protobuf-java:$protobufVersion" + compile "com.google.api.grpc:proto-google-common-protos:$commonProtosVersion" + + // FIXME Not clear which of the following libs have a newer version of guava which is not compatible with ours + compile ("io.grpc:grpc-alts:$grpcVersion") { + exclude(module: 'guava') + } + + compile ("io.grpc:grpc-netty:$grpcVersion") { + exclude(module: 'guava') + } + + + compile ("io.grpc:grpc-protobuf:$grpcVersion") { + exclude(module: 'guava') + } + + compile ("io.grpc:grpc-stub:$grpcVersion") { + exclude(module: 'guava') + } + + // Used for TLS in HelloWorldServerTls + compile "io.netty:netty-tcnative-boringssl-static:${nettyTcNativeVersion}" + + compileOnly "org.projectlombok:lombok:$lombokVersion" + compileOnly "javax.annotation:javax.annotation-api:1.2" + annotationProcessor "org.projectlombok:lombok:$lombokVersion" + + testCompile "io.grpc:grpc-testing:${grpcVersion}" + testCompile "org.mockito:mockito-core:$mockitoVersion" + testCompile "org.springframework:spring-test:$springVersion" + testCompile "com.natpryce:make-it-easy:$easyVersion" + testCompileOnly "org.projectlombok:lombok:$lombokVersion" + testAnnotationProcessor "org.projectlombok:lombok:$lombokVersion" + } +} diff --git a/core/src/main/java/bisq/core/CoreApi.java b/core/src/main/java/bisq/core/CoreApi.java new file mode 100644 index 00000000000..09d67e495ed --- /dev/null +++ b/core/src/main/java/bisq/core/CoreApi.java @@ -0,0 +1,163 @@ +/* + * This file is part of Bisq. + * + * Bisq is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Bisq is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Bisq. If not, see . + */ + +package bisq.core; + +import bisq.core.btc.Balances; +import bisq.core.monetary.Price; +import bisq.core.offer.CreateOfferService; +import bisq.core.offer.Offer; +import bisq.core.offer.OfferBookService; +import bisq.core.offer.OfferPayload; +import bisq.core.offer.OpenOfferManager; +import bisq.core.payment.PaymentAccount; +import bisq.core.presentation.BalancePresentation; +import bisq.core.trade.handlers.TransactionResultHandler; +import bisq.core.trade.statistics.TradeStatistics2; +import bisq.core.trade.statistics.TradeStatisticsManager; +import bisq.core.user.User; + +import bisq.common.app.Version; + +import org.bitcoinj.core.Coin; + +import javax.inject.Inject; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +import lombok.extern.slf4j.Slf4j; + +/** + * Provides high level interface to functionality of core Bisq features. + * E.g. useful for different APIs to access data of different domains of Bisq. + */ +@Slf4j +public class CoreApi { + private final Balances balances; + private final BalancePresentation balancePresentation; + private final OfferBookService offerBookService; + private final TradeStatisticsManager tradeStatisticsManager; + private final CreateOfferService createOfferService; + private final OpenOfferManager openOfferManager; + private final User user; + + @Inject + public CoreApi(Balances balances, + BalancePresentation balancePresentation, + OfferBookService offerBookService, + TradeStatisticsManager tradeStatisticsManager, + CreateOfferService createOfferService, + OpenOfferManager openOfferManager, + User user) { + this.balances = balances; + this.balancePresentation = balancePresentation; + this.offerBookService = offerBookService; + this.tradeStatisticsManager = tradeStatisticsManager; + this.createOfferService = createOfferService; + this.openOfferManager = openOfferManager; + this.user = user; + } + + public String getVersion() { + return Version.VERSION; + } + + public long getAvailableBalance() { + return balances.getAvailableBalance().get().getValue(); + } + + public String getAvailableBalanceAsString() { + return balancePresentation.getAvailableBalance().get(); + } + + public List getTradeStatistics() { + return new ArrayList<>(tradeStatisticsManager.getObservableTradeStatisticsSet()); + } + + public List getOffers() { + return offerBookService.getOffers(); + } + + public Set getPaymentAccounts() { + return user.getPaymentAccounts(); + } + + public void placeOffer(String currencyCode, + String directionAsString, + long priceAsLong, + boolean useMarketBasedPrice, + double marketPriceMargin, + long amountAsLong, + long minAmountAsLong, + double buyerSecurityDeposit, + String paymentAccountId, + TransactionResultHandler resultHandler) { + String offerId = createOfferService.getRandomOfferId(); + OfferPayload.Direction direction = OfferPayload.Direction.valueOf(directionAsString); + Price price = Price.valueOf(currencyCode, priceAsLong); + Coin amount = Coin.valueOf(amountAsLong); + Coin minAmount = Coin.valueOf(minAmountAsLong); + PaymentAccount paymentAccount = user.getPaymentAccount(paymentAccountId); + // We don't support atm funding from external wallet to keep it simple + boolean useSavingsWallet = true; + + placeOffer(offerId, + currencyCode, + direction, + price, + useMarketBasedPrice, + marketPriceMargin, + amount, + minAmount, + buyerSecurityDeposit, + paymentAccount, + useSavingsWallet, + resultHandler); + } + + public void placeOffer(String offerId, + String currencyCode, + OfferPayload.Direction direction, + Price price, + boolean useMarketBasedPrice, + double marketPriceMargin, + Coin amount, + Coin minAmount, + double buyerSecurityDeposit, + PaymentAccount paymentAccount, + boolean useSavingsWallet, + TransactionResultHandler resultHandler) { + Offer offer = createOfferService.createAndGetOffer(offerId, + direction, + currencyCode, + amount, + minAmount, + price, + useMarketBasedPrice, + marketPriceMargin, + buyerSecurityDeposit, + paymentAccount); + + openOfferManager.placeOffer(offer, + buyerSecurityDeposit, + useSavingsWallet, + resultHandler, + log::error); + } +} diff --git a/desktop/src/main/java/bisq/desktop/app/BisqAppMain.java b/desktop/src/main/java/bisq/desktop/app/BisqAppMain.java index a2494dfbdb1..cccaf5a63b4 100644 --- a/desktop/src/main/java/bisq/desktop/app/BisqAppMain.java +++ b/desktop/src/main/java/bisq/desktop/app/BisqAppMain.java @@ -21,6 +21,7 @@ import bisq.desktop.common.view.guice.InjectorViewFactory; import bisq.desktop.setup.DesktopPersistedDataHost; +import bisq.core.CoreApi; import bisq.core.app.BisqExecutable; import bisq.common.UserThread; @@ -36,6 +37,12 @@ import lombok.extern.slf4j.Slf4j; +import javax.annotation.Nullable; + + + +import bisq.grpc.BisqGrpcServer; + @Slf4j public class BisqAppMain extends BisqExecutable { private BisqApp application; @@ -46,9 +53,9 @@ public BisqAppMain() { /* @Nullable private BisqHttpApiServer bisqHttpApiServer;*/ - /* @Nullable + @Nullable private BisqGrpcServer bisqGrpcServer; - */ + public static void main(String[] args) throws Exception { if (BisqExecutable.setupInitialOptionParser(args)) { // For some reason the JavaFX launch process results in us losing the thread context class loader: reset it. @@ -138,10 +145,11 @@ protected void onApplicationStarted() { /* if (runWithHttpApi()) { bisqHttpApiServer = new BisqHttpApiServer(); }*/ - /* + if (runWithGrpcApi()) { - bisqGrpcServer = new BisqGrpcServer(); - }*/ + CoreApi coreApi = injector.getInstance(CoreApi.class); + bisqGrpcServer = new BisqGrpcServer(coreApi); + } } private boolean runWithHttpApi() { diff --git a/gradle/witness/gradle-witness.gradle b/gradle/witness/gradle-witness.gradle index 19d1f00cfb4..423c357f312 100644 --- a/gradle/witness/gradle-witness.gradle +++ b/gradle/witness/gradle-witness.gradle @@ -11,14 +11,13 @@ // // See https://github.com/signalapp/gradle-witness#using-witness for further details. - dependencyVerification { verify = [ 'aopalliance:aopalliance:0addec670fedcd3f113c5c8091d783280d23f75e3acb841b61a9cdb079376a08', 'ch.qos.logback:logback-classic:e66efc674e94837344bc5b748ff510c37a44eeff86cbfdbf9e714ef2eb374013', 'ch.qos.logback:logback-core:4cd46fa17d77057b39160058df2f21ebbc2aded51d0edcc25d2c1cecc042a005', 'com.fasterxml.jackson.core:jackson-annotations:2566b3a6662afa3c6af4f5b25006cb46be2efc68f1b5116291d6998a8cdf7ed3', - 'com.fasterxml.jackson.core:jackson-core:39a74610521d7fb9eb3f437bb8739bbf47f6435be12d17bf954c731a0c6352bb', + 'com.fasterxml.jackson.core:jackson-core:3083079be6088db2ed0a0c6ff92204e0aa48fa1de9db5b59c468f35acf882c2c', 'com.fasterxml.jackson.core:jackson-databind:fcf3c2b0c332f5f54604f7e27fa7ee502378a2cc5df6a944bbfae391872c32ff', 'com.github.JesusMcCloud.netlayer:tor.external:10c3acfbcf8f80154a3f10640c4d4d275c4fc9baaf5c476d631da4e2382aaa5b', 'com.github.JesusMcCloud.netlayer:tor.native:fba4dca6a139af741c36713bcfe3680a92870009dbb59a3a14f9dae7f6cd116e', @@ -32,11 +31,21 @@ dependencyVerification { 'com.github.bisq-network.bitcoinj:bitcoinj-core:f979c2187e61ee3b08dd4cbfc49a149734cff64c045d29ed112f2e12f34068a3', 'com.github.ravn:jsocks:3c71600af027b2b6d4244e4ad14d98ff2352a379410daebefff5d8cd48d742a4', 'com.github.sarxos:webcam-capture:d960b7ea8ec3ddf2df0725ef214c3fccc9699ea7772df37f544e1f8e4fd665f6', + 'com.google.android:annotations:ba734e1e84c09d615af6a09d33034b4f0442f8772dec120efb376d86a565ae15', + 'com.google.api.grpc:proto-google-common-protos:ad25472c73ee470606fb500b376ae5a97973d5406c2f5c3b7d07fb25b4648b65', + 'com.google.auth:google-auth-library-credentials:aaeea9333fff9b763715bca0174ec76c4f9551b5731c89a95f263cdc82b4b56e', + 'com.google.auth:google-auth-library-oauth2-http:fa9a1589c8bc279416988d437c2636967cd5e4eff70fbddc986b9c5a77b0231b', + 'com.google.auto.value:auto-value-annotations:3bf4b9e74a6bf0f38ac70af571e0f8a9d85ccba4c0693a72fea9ea46def0d5a0', 'com.google.code.findbugs:jsr305:766ad2a0783f2687962c8ad74ceecc38a28b9f72a2d085ee438b7813e928d0c7', - 'com.google.code.gson:gson:2d43eb5ea9e133d2ee2405cc14f5ee08951b8361302fdd93494a3a997b508d32', + 'com.google.code.gson:gson:233a0149fc365c9f6edbd683cfe266b19bdc773be98eabdaf6b3c924b48e7d81', + 'com.google.errorprone:error_prone_annotations:ec59f1b702d9afc09e8c3929f5c42777dec623a6ea2731ac694332c7d7680f5a', 'com.google.guava:guava:36a666e3b71ae7f0f0dca23654b67e086e6c93d192f60ba5dfd5519db6c288c8', + 'com.google.http-client:google-http-client-jackson2:480b67711dd75054b45ec4f88056e53fda9773145117a1a852c803e2cb4b84e0', + 'com.google.http-client:google-http-client:2b4353d8ca918f92f3a5fcd6b6b2de09858eae683423225773f24c828cd06cc8', 'com.google.inject:guice:d258ff1bd9b8b527872f8402648226658ad3149f1f40e74b0566d69e7e042fbc', - 'com.google.protobuf:protobuf-java:5a1e5c225791eccd3d67a598922e637406190c90155fb97f38e4eab29719324d', + 'com.google.j2objc:j2objc-annotations:21af30c92267bd6122c0e0b4d20cccb6641a37eaf956c6540ec471d584e64a7b', + 'com.google.protobuf:protobuf-java-util:619b0b0dc344cb141e493cbedc5687c8fb7c985e609a1b035e621bfab2f89021', + 'com.google.protobuf:protobuf-java:161d7d61a8cb3970891c299578702fd079646e032329d6c2cabf998d191437c9', 'com.google.zxing:core:11aae8fd974ab25faa8208be50468eb12349cd239e93e7c797377fa13e381729', 'com.google.zxing:javase:0ec23e2ec12664ddd6347c8920ad647bb3b9da290f897a88516014b56cc77eb9', 'com.googlecode.jcsv:jcsv:73ca7d715e90c8d2c2635cc284543b038245a34f70790660ed590e157b8714a2', @@ -46,13 +55,39 @@ dependencyVerification { 'com.nativelibs4java:bridj:101bcd9b6637e6bc16e56deb3daefba62b1f5e8e9e37e1b3e56e3b5860d659cf', 'com.squareup.okhttp:okhttp:b4c943138fcef2bcc9d2006b2250c4aabbedeafc5947ed7c0af7fd103ceb2707', 'com.squareup.okio:okio:114bdc1f47338a68bcbc95abf2f5cdc72beeec91812f2fcd7b521c1937876266', - 'commons-codec:commons-codec:ad19d2601c3abf0b946b5c3a4113e226a8c1e3305e395b90013b78dd94a723ce', + 'commons-codec:commons-codec:e599d5318e97aa48f42136a2927e6dfa4e8881dff0e6c8e3109ddbbff51d7b7d', 'commons-io:commons-io:cc6a41dc3eaacc9e440a6bd0d2890b20d36b4ee408fe2d67122f328bb6e01581', 'commons-logging:commons-logging:daddea1ea0be0f56978ab3006b8ac92834afeefbd9b7e4e6316fca57df0fa636', 'de.jensd:fontawesomefx-commons:5539bb3335ecb822dbf928546f57766eeb9f1516cc1417a064b5709629612149', 'de.jensd:fontawesomefx-materialdesignfont:dbad8dfdd1c85e298d5bbae25b2399aec9e85064db57b2427d10f3815aa98752', 'de.jensd:fontawesomefx:73bacc991a0a6f5cf0f911767c8db161e0949dbca61e8371eb4342e3da96887b', 'io.github.microutils:kotlin-logging:4992504fd3c6ecdf9ed10874b9508e758bb908af9e9d7af19a61e9afb6b7e27a', + 'io.grpc:grpc-alts:177aa1e578c10e274f8feedd6f555c2e7741c195a84f533f9a51fb82dbe8a596', + 'io.grpc:grpc-api:a269094009588213ab5386a6fb92426b8056a130b2653d3b4e59e971f2f1ef08', + 'io.grpc:grpc-auth:782ae07923d53b56f54326e7b32480b425eb3df71deb5a4a33bbfc6487e706a4', + 'io.grpc:grpc-context:f4c8f878c320f6fb56c1c14692618f6df8253314b556176e32727afbc5921a73', + 'io.grpc:grpc-core:d67fa113fd9cc45a02710f9c41dda9c15191448c14e9e96fcc21839a41345d4c', + 'io.grpc:grpc-grpclb:aaac0d6063204dfc52abc51af94f16b6cecfd582bb477ee1d232e42920bf49e3', + 'io.grpc:grpc-netty-shaded:9edfd45da473d2efbb5683fc3eaf1857e82d2148033d82dd558a7ac38731ea33', + 'io.grpc:grpc-netty:167e834788f6d4f7bd129bfb244d4e09d061a0e7165288378386ae871e3cfe51', + 'io.grpc:grpc-protobuf-lite:9ba9aaa3e6997a04c707793c25e3ec88c6bad86f8d6f6b8b7a1a0c33ea2429d8', + 'io.grpc:grpc-protobuf:454dae7e246dac25526ed5b795d97a5dafedd3cc2042cfc810f02051d7d3e3cb', + 'io.grpc:grpc-stub:1532e291c0e9fd8230a6416c8ebbd902d99c7e2760241ae638ea761aa3dd5f43', + 'io.netty:netty-buffer:7b0171a4e8bcd573e08d9f2bba053c67b557ab5012106a5982ccbae5743814c0', + 'io.netty:netty-codec-http2:8bac9625eb68635396eb0c13c9cc0b22bde7c83d0cd2dae3fe9b6f9cf929e372', + 'io.netty:netty-codec-http:eb349c0f1b249af7c7a8fbbd1c761d65d9bc230880cd8d37feab9e8278292625', + 'io.netty:netty-codec-socks:7f14b3a95ee9aa5a26f66af668690578a81a883683ac1c4ca9e9afdf4d4c7894', + 'io.netty:netty-codec:e96ced697fb7df589da7c20c995e01f75a9cb246be242bbc4cd3b4af424ff189', + 'io.netty:netty-common:3d0a918d78292eeca02a7bb2188daa4e5053b6e29b71e6308309033e121242b5', + 'io.netty:netty-handler-proxy:25f22da21c29ab0d3b6b889412351bcfc5f9ccd42e07d2d5513d5c4eb571f343', + 'io.netty:netty-handler:11eda86500c33b9d386719b5419f513fd9c097d13894f25dd0c75b610d636e03', + 'io.netty:netty-resolver:89768242b6b7cce9bd9f5945ad21d1b4bae515c6b1bf03a8af5d1899779cebc9', + 'io.netty:netty-tcnative-boringssl-static:0ea1a935a1023a88e99a4f9b1aba2e3ff2799d4d1994f4bff848f85b367d48ed', + 'io.netty:netty-transport:dfa817a156ea263aa9ad8364a2e226527665c9722aca40a7945f228c2c14f1da', + 'io.opencensus:opencensus-api:8e2cb0f6391d8eb0a1bcd01e7748883f0033b1941754f4ed3f19d2c3e4276fc8', + 'io.opencensus:opencensus-contrib-grpc-metrics:29fc79401082301542cab89d7054d2f0825f184492654c950020553ef4ff0ef8', + 'io.opencensus:opencensus-contrib-http-util:d62fd27175a842bde135f6f6b1d6f25d42e9bd59a87bc98709a4760fe399ee14', + 'io.perfmark:perfmark-api:b734ba2149712409a44eabdb799f64768578fee0defe1418bb108fe32ea43e1a', 'javax.inject:javax.inject:91c77044a50c481636c32d916fd89c9118a72195390452c81065080f957de7ff', 'net.glxn:qrgen:c85d9d8512d91e8ad11fe56259a7825bd50ce0245447e236cf168d1b17591882', 'net.jcip:jcip-annotations:be5805392060c71474bf6c9a67a099471274d30b83eef84bfc4e0889a4f1dcc0', @@ -60,12 +95,14 @@ dependencyVerification { 'network.bisq.btcd-cli4j:btcd-cli4j-core:203156fc63dc1202774de9818e4f21149549f79b25d356b08bb0c784be40c0e8', 'network.bisq.btcd-cli4j:btcd-cli4j-daemon:0a2783a851add6e3d8ae899ade48c041b250bfac64b6a4c5f6380ebcdbbe6848', 'org.apache.commons:commons-compress:5f2df1e467825e4cac5996d44890c4201c000b43c0b23cffc0782d28a0beb9b0', - 'org.apache.commons:commons-lang3:734c8356420cc8e30c795d64fd1fcd5d44ea9d90342a2cc3262c5158fbc6d98b', - 'org.apache.httpcomponents:httpclient:db3d1b6c2d6a5e5ad47577ad61854e2f0e0936199b8e05eb541ed52349263135', - 'org.apache.httpcomponents:httpcore:d7f853dee87680b07293d30855b39b9eb56c1297bd16ff1cd6f19ddb8fa745fb', + 'org.apache.commons:commons-lang3:8ac96fc686512d777fca85e144f196cd7cfe0c0aec23127229497d1a38ff651c', + 'org.apache.httpcomponents:httpclient:6c7e3bb423d8c5574f28157fe42b4c38d6a3477bfa2954cfe5f330b14ecad8a9', + 'org.apache.httpcomponents:httpcore:d799522d579aac06b170603f8f080f6e3248dadc01f9652cdd7ea7bc318c21ce', 'org.bitcoinj:orchid:f836325cfa0466a011cb755c9b0fee6368487a2352eb45f4306ad9e4c18de080', 'org.bouncycastle:bcpg-jdk15on:de3355b821fc81dd32e1f3f560d5b3eca1c678fd2400011d0bfc69fb91bcde85', 'org.bouncycastle:bcprov-jdk15on:963e1ee14f808ffb99897d848ddcdb28fa91ddda867eb18d303e82728f878349', + 'org.codehaus.mojo:animal-sniffer-annotations:92654f493ecfec52082e76354f0ebf87648dc3d5cec2e3c3cdb947c016747a53', + 'org.conscrypt:conscrypt-openjdk-uber:27f4314bf01e5af288ade537f06cb6eb7f0c760aed4a8d7cf441de71de0a7abb', 'org.fxmisc.easybind:easybind:666af296dda6de68751668a62661571b5238ac6f1c07c8a204fc6f902b222aaf', 'org.jetbrains.kotlin:kotlin-stdlib-common:6c91dea17d7dce5f0b550c3de3305767e5fb46247b6d1eb7eca0ca1fe18458de', 'org.jetbrains.kotlin:kotlin-stdlib-jdk7:25e2409aba0ec37d2fd7c77727d7835b511879de8d9bf4862af0b493aabbe39e', diff --git a/grpc/src/main/java/bisq/grpc/BisqGrpcApp.java b/grpc/src/main/java/bisq/grpc/BisqGrpcApp.java new file mode 100644 index 00000000000..b95bd2b1926 --- /dev/null +++ b/grpc/src/main/java/bisq/grpc/BisqGrpcApp.java @@ -0,0 +1,26 @@ +/* + * 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.grpc; + +import bisq.core.app.BisqHeadlessApp; + +/** + * Headless Bisq application. Only used if gRPC API runs in headless mode. + */ +public class BisqGrpcApp extends BisqHeadlessApp { +} diff --git a/grpc/src/main/java/bisq/grpc/BisqGrpcClient.java b/grpc/src/main/java/bisq/grpc/BisqGrpcClient.java new file mode 100644 index 00000000000..d3d698cf791 --- /dev/null +++ b/grpc/src/main/java/bisq/grpc/BisqGrpcClient.java @@ -0,0 +1,297 @@ +/* + * 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.grpc; + +import bisq.core.payment.PaymentAccount; +import bisq.core.proto.network.CoreNetworkProtoResolver; +import bisq.core.proto.persistable.CorePersistenceProtoResolver; + +import org.bitcoinj.core.Coin; + +import java.time.Clock; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Scanner; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; + +import lombok.extern.slf4j.Slf4j; + +import static com.google.common.base.Preconditions.checkArgument; + + + +import bisq.grpc.protobuf.GetBalanceGrpc; +import bisq.grpc.protobuf.GetBalanceRequest; +import bisq.grpc.protobuf.GetOffersGrpc; +import bisq.grpc.protobuf.GetOffersRequest; +import bisq.grpc.protobuf.GetPaymentAccountsGrpc; +import bisq.grpc.protobuf.GetPaymentAccountsRequest; +import bisq.grpc.protobuf.GetTradeStatisticsGrpc; +import bisq.grpc.protobuf.GetTradeStatisticsRequest; +import bisq.grpc.protobuf.GetVersionGrpc; +import bisq.grpc.protobuf.GetVersionRequest; +import bisq.grpc.protobuf.PlaceOfferGrpc; +import bisq.grpc.protobuf.PlaceOfferRequest; +import bisq.grpc.protobuf.StopServerGrpc; +import bisq.grpc.protobuf.StopServerRequest; +import io.grpc.ManagedChannel; +import io.grpc.ManagedChannelBuilder; +import io.grpc.StatusRuntimeException; + +/** + * gRPC client. + * + * FIXME We get warning 'DEBUG io.grpc.netty.shaded.io.netty.util.internal.PlatformDependent0 - direct buffer constructor: unavailable + * java.lang.UnsupportedOperationException: Reflective setAccessible(true) disabled' which is + * related to Java 10 changes. Requests are working but we should find out why we get that warning + */ +@Slf4j +public class BisqGrpcClient { + private static BisqGrpcClient instance; + + private final ManagedChannel channel; + private final GetVersionGrpc.GetVersionBlockingStub getVersionStub; + private final GetBalanceGrpc.GetBalanceBlockingStub getBalanceStub; + private final StopServerGrpc.StopServerBlockingStub stopServerStub; + private final GetTradeStatisticsGrpc.GetTradeStatisticsBlockingStub getTradeStatisticsStub; + private final GetOffersGrpc.GetOffersBlockingStub getOffersStub; + private final GetPaymentAccountsGrpc.GetPaymentAccountsBlockingStub getPaymentAccountsStub; + private final PlaceOfferGrpc.PlaceOfferBlockingStub placeOfferBlockingStub; + private final CorePersistenceProtoResolver corePersistenceProtoResolver; + private final CoreNetworkProtoResolver coreNetworkProtoResolver; + + public static void main(String[] args) throws Exception { + instance = new BisqGrpcClient("localhost", 8888); + } + + private BisqGrpcClient(String host, int port) { + this(ManagedChannelBuilder.forAddress(host, port) + // Channels are secure by default (via SSL/TLS). For the example we disable TLS to avoid + // needing certificates. + .usePlaintext(true).build()); + + // Simple input scanner + // TODO use some more sophisticated input processing with validation.... + try (Scanner scanner = new Scanner(System.in);) { + while (true) { + long startTs = System.currentTimeMillis(); + + String[] tokens = scanner.nextLine().split(" "); + if (tokens.length == 0) { + return; + } + String command = tokens[0]; + List params = new ArrayList<>(); + if (tokens.length > 1) { + params.addAll(Arrays.asList(tokens)); + params.remove(0); + } + String result = ""; + + switch (command) { + case "getVersion": + result = getVersion(); + break; + case "getBalance": + result = Coin.valueOf(getBalance()).toFriendlyString(); + break; + case "getTradeStatistics": + List tradeStatistics = getTradeStatistics().stream() + .map(bisq.core.trade.statistics.TradeStatistics2::fromProto) + .collect(Collectors.toList()); + + result = tradeStatistics.toString(); + break; + case "getOffers": + List offers = getOffers().stream() + .map(bisq.core.offer.Offer::fromProto) + .collect(Collectors.toList()); + result = offers.toString(); + break; + case "getPaymentAccounts": + List paymentAccounts = getPaymentAccounts().stream() + .map(proto -> PaymentAccount.fromProto(proto, corePersistenceProtoResolver)) + .collect(Collectors.toList()); + result = paymentAccounts.toString(); + break; + case "placeOffer": + // test input: placeOffer CNY BUY 750000000 true -0.2251 1000000 500000 0.12 5a972121-c30a-4b0e-b519-b17b63795d16 + // payment accountId and currency need to be adopted + + // We expect 9 params + // TODO add basic input validation + try { + checkArgument(params.size() == 9); + String currencyCode = params.get(0); + String directionAsString = params.get(1); + long priceAsLong = Long.parseLong(params.get(2)); + boolean useMarketBasedPrice = Boolean.parseBoolean(params.get(3)); + double marketPriceMargin = Double.parseDouble(params.get(4)); + long amountAsLong = Long.parseLong(params.get(5)); + long minAmountAsLong = Long.parseLong(params.get(6)); + double buyerSecurityDeposit = Double.parseDouble(params.get(7)); + String paymentAccountId = params.get(8); + boolean success = placeOffer(currencyCode, + directionAsString, + priceAsLong, + useMarketBasedPrice, + marketPriceMargin, + amountAsLong, + minAmountAsLong, + buyerSecurityDeposit, + paymentAccountId); + result = String.valueOf(success); + break; + } catch (Throwable t) { + log.error(t.toString(), t); + break; + } + case "stop": + result = "Shut down client"; + try { + shutdown(); + } catch (InterruptedException e) { + log.error(e.toString(), e); + } + break; + case "stopServer": + stopServer(); + result = "Server stopped"; + break; + } + + // First response is rather slow (300 ms) but following responses are fast (3-5 ms). + log.info("Request took: {} ms", System.currentTimeMillis() - startTs); + log.info(result); + } + } + } + + /** + * Construct client for accessing server using the existing channel. + */ + private BisqGrpcClient(ManagedChannel channel) { + this.channel = channel; + + getVersionStub = GetVersionGrpc.newBlockingStub(channel); + getBalanceStub = GetBalanceGrpc.newBlockingStub(channel); + getTradeStatisticsStub = GetTradeStatisticsGrpc.newBlockingStub(channel); + getOffersStub = GetOffersGrpc.newBlockingStub(channel); + getPaymentAccountsStub = GetPaymentAccountsGrpc.newBlockingStub(channel); + placeOfferBlockingStub = PlaceOfferGrpc.newBlockingStub(channel); + stopServerStub = StopServerGrpc.newBlockingStub(channel); + + coreNetworkProtoResolver = new CoreNetworkProtoResolver(Clock.systemDefaultZone()); + //TODO + corePersistenceProtoResolver = new CorePersistenceProtoResolver(null, coreNetworkProtoResolver, null, null); + } + + private String getVersion() { + GetVersionRequest request = GetVersionRequest.newBuilder().build(); + try { + return getVersionStub.getVersion(request).getVersion(); + } catch (StatusRuntimeException e) { + return "RPC failed: " + e.getStatus(); + } + } + + private long getBalance() { + GetBalanceRequest request = GetBalanceRequest.newBuilder().build(); + try { + return getBalanceStub.getBalance(request).getBalance(); + } catch (StatusRuntimeException e) { + log.warn("RPC failed: {}", e.getStatus()); + return -1; + } + } + + private List getTradeStatistics() { + GetTradeStatisticsRequest request = GetTradeStatisticsRequest.newBuilder().build(); + try { + return getTradeStatisticsStub.getTradeStatistics(request).getTradeStatisticsList(); + } catch (StatusRuntimeException e) { + log.warn("RPC failed: {}", e.getStatus()); + return null; + } + } + + private List getOffers() { + GetOffersRequest request = GetOffersRequest.newBuilder().build(); + try { + return getOffersStub.getOffers(request).getOffersList(); + } catch (StatusRuntimeException e) { + log.warn("RPC failed: {}", e.getStatus()); + return null; + } + } + + private List getPaymentAccounts() { + GetPaymentAccountsRequest request = GetPaymentAccountsRequest.newBuilder().build(); + try { + return getPaymentAccountsStub.getPaymentAccounts(request).getPaymentAccountsList(); + } catch (StatusRuntimeException e) { + log.warn("RPC failed: {}", e.getStatus()); + return null; + } + } + + private boolean placeOffer(String currencyCode, + String directionAsString, + long priceAsLong, + boolean useMarketBasedPrice, + double marketPriceMargin, + long amountAsLong, + long minAmountAsLong, + double buyerSecurityDeposit, + String paymentAccountId) { + PlaceOfferRequest request = PlaceOfferRequest.newBuilder() + .setCurrencyCode(currencyCode) + .setDirection(directionAsString) + .setPrice(priceAsLong) + .setUseMarketBasedPrice(useMarketBasedPrice) + .setMarketPriceMargin(marketPriceMargin) + .setAmount(amountAsLong) + .setMinAmount(minAmountAsLong) + .setBuyerSecurityDeposit(buyerSecurityDeposit) + .setPaymentAccountId(paymentAccountId) + .build(); + try { + return placeOfferBlockingStub.placeOffer(request).getResult(); + } catch (StatusRuntimeException e) { + log.warn("RPC failed: {}", e.getStatus()); + return false; + } + } + + private void stopServer() { + StopServerRequest request = StopServerRequest.newBuilder().build(); + try { + stopServerStub.stopServer(request); + } catch (StatusRuntimeException e) { + log.warn("RPC failed: {}", e.getStatus()); + } + } + + private void shutdown() throws InterruptedException { + channel.shutdown().awaitTermination(1, TimeUnit.SECONDS); + System.exit(0); + } +} diff --git a/grpc/src/main/java/bisq/grpc/BisqGrpcServer.java b/grpc/src/main/java/bisq/grpc/BisqGrpcServer.java new file mode 100644 index 00000000000..293fe91e47d --- /dev/null +++ b/grpc/src/main/java/bisq/grpc/BisqGrpcServer.java @@ -0,0 +1,236 @@ +/* + * 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.grpc; + +import bisq.core.CoreApi; +import bisq.core.offer.Offer; +import bisq.core.payment.PaymentAccount; +import bisq.core.trade.handlers.TransactionResultHandler; +import bisq.core.trade.statistics.TradeStatistics2; + +import java.io.IOException; + +import java.util.List; +import java.util.stream.Collectors; + +import lombok.extern.slf4j.Slf4j; + + + +import bisq.grpc.protobuf.GetBalanceGrpc; +import bisq.grpc.protobuf.GetBalanceReply; +import bisq.grpc.protobuf.GetBalanceRequest; +import bisq.grpc.protobuf.GetOffersGrpc; +import bisq.grpc.protobuf.GetOffersReply; +import bisq.grpc.protobuf.GetOffersRequest; +import bisq.grpc.protobuf.GetPaymentAccountsGrpc; +import bisq.grpc.protobuf.GetPaymentAccountsReply; +import bisq.grpc.protobuf.GetPaymentAccountsRequest; +import bisq.grpc.protobuf.GetTradeStatisticsGrpc; +import bisq.grpc.protobuf.GetTradeStatisticsReply; +import bisq.grpc.protobuf.GetTradeStatisticsRequest; +import bisq.grpc.protobuf.GetVersionGrpc; +import bisq.grpc.protobuf.GetVersionReply; +import bisq.grpc.protobuf.GetVersionRequest; +import bisq.grpc.protobuf.PlaceOfferGrpc; +import bisq.grpc.protobuf.PlaceOfferReply; +import bisq.grpc.protobuf.PlaceOfferRequest; +import bisq.grpc.protobuf.StopServerGrpc; +import bisq.grpc.protobuf.StopServerReply; +import bisq.grpc.protobuf.StopServerRequest; +import io.grpc.Server; +import io.grpc.ServerBuilder; +import io.grpc.stub.StreamObserver; + +/** + * gRPC server. Gets a instance of BisqFacade passed to access data from the running Bisq instance. + */ +@Slf4j +public class BisqGrpcServer { + + private Server server; + + private static BisqGrpcServer instance; + private static CoreApi coreApi; + + + /////////////////////////////////////////////////////////////////////////////////////////// + // Services + /////////////////////////////////////////////////////////////////////////////////////////// + + static class GetVersionImpl extends GetVersionGrpc.GetVersionImplBase { + @Override + public void getVersion(GetVersionRequest req, StreamObserver responseObserver) { + GetVersionReply reply = GetVersionReply.newBuilder().setVersion(coreApi.getVersion()).build(); + responseObserver.onNext(reply); + responseObserver.onCompleted(); + } + } + + static class GetBalanceImpl extends GetBalanceGrpc.GetBalanceImplBase { + @Override + public void getBalance(GetBalanceRequest req, StreamObserver responseObserver) { + GetBalanceReply reply = GetBalanceReply.newBuilder().setBalance(coreApi.getAvailableBalance()).build(); + responseObserver.onNext(reply); + responseObserver.onCompleted(); + } + } + + static class GetTradeStatisticsImpl extends GetTradeStatisticsGrpc.GetTradeStatisticsImplBase { + @Override + public void getTradeStatistics(GetTradeStatisticsRequest req, + StreamObserver responseObserver) { + List tradeStatistics = coreApi.getTradeStatistics().stream() + .map(TradeStatistics2::toProtoTradeStatistics2) + .collect(Collectors.toList()); + GetTradeStatisticsReply reply = GetTradeStatisticsReply.newBuilder().addAllTradeStatistics(tradeStatistics).build(); + responseObserver.onNext(reply); + responseObserver.onCompleted(); + } + } + + static class GetOffersImpl extends GetOffersGrpc.GetOffersImplBase { + @Override + public void getOffers(GetOffersRequest req, StreamObserver responseObserver) { + + List tradeStatistics = coreApi.getOffers().stream() + .map(Offer::toProtoMessage) + .collect(Collectors.toList()); + + GetOffersReply reply = GetOffersReply.newBuilder().addAllOffers(tradeStatistics).build(); + responseObserver.onNext(reply); + responseObserver.onCompleted(); + } + } + + static class GetPaymentAccountsImpl extends GetPaymentAccountsGrpc.GetPaymentAccountsImplBase { + @Override + public void getPaymentAccounts(GetPaymentAccountsRequest req, + StreamObserver responseObserver) { + + List tradeStatistics = coreApi.getPaymentAccounts().stream() + .map(PaymentAccount::toProtoMessage) + .collect(Collectors.toList()); + + GetPaymentAccountsReply reply = GetPaymentAccountsReply.newBuilder().addAllPaymentAccounts(tradeStatistics).build(); + responseObserver.onNext(reply); + responseObserver.onCompleted(); + } + } + + static class PlaceOfferImpl extends PlaceOfferGrpc.PlaceOfferImplBase { + @Override + public void placeOffer(PlaceOfferRequest req, StreamObserver responseObserver) { + TransactionResultHandler resultHandler = transaction -> { + PlaceOfferReply reply = PlaceOfferReply.newBuilder().setResult(true).build(); + responseObserver.onNext(reply); + responseObserver.onCompleted(); + }; + coreApi.placeOffer( + req.getCurrencyCode(), + req.getDirection(), + req.getPrice(), + req.getUseMarketBasedPrice(), + req.getMarketPriceMargin(), + req.getAmount(), + req.getMinAmount(), + req.getBuyerSecurityDeposit(), + req.getPaymentAccountId(), + resultHandler); + } + } + + static class StopServerImpl extends StopServerGrpc.StopServerImplBase { + @Override + public void stopServer(StopServerRequest req, StreamObserver responseObserver) { + StopServerReply reply = StopServerReply.newBuilder().build(); + responseObserver.onNext(reply); + responseObserver.onCompleted(); + + instance.stop(); + } + } + + + /////////////////////////////////////////////////////////////////////////////////////////// + // Constructor + /////////////////////////////////////////////////////////////////////////////////////////// + + public BisqGrpcServer(CoreApi coreApi) { + instance = this; + + BisqGrpcServer.coreApi = coreApi; + + try { + start(); + + } catch (IOException e) { + log.error(e.toString(), e); + } + } + + + /////////////////////////////////////////////////////////////////////////////////////////// + // API + /////////////////////////////////////////////////////////////////////////////////////////// + + public void stop() { + if (server != null) { + server.shutdown(); + } + } + + /** + * Await termination on the main thread since the grpc library uses daemon threads. + * Only used for headless version + */ + void blockUntilShutdown() throws InterruptedException { + if (server != null) { + server.awaitTermination(); + } + } + + /////////////////////////////////////////////////////////////////////////////////////////// + // Private + /////////////////////////////////////////////////////////////////////////////////////////// + + private void start() throws IOException { + // TODO add to options + int port = 8888; + + // Config services + server = ServerBuilder.forPort(port) + .addService(new GetVersionImpl()) + .addService(new GetBalanceImpl()) + .addService(new GetTradeStatisticsImpl()) + .addService(new GetOffersImpl()) + .addService(new GetPaymentAccountsImpl()) + .addService(new PlaceOfferImpl()) + .addService(new StopServerImpl()) + .build() + .start(); + + log.info("Server started, listening on " + port); + Runtime.getRuntime().addShutdownHook(new Thread(() -> { + // Use stderr here since the logger may have been reset by its JVM shutdown hook. + log.error("*** shutting down gRPC server since JVM is shutting down"); + BisqGrpcServer.this.stop(); + log.error("*** server shut down"); + })); + } +} diff --git a/grpc/src/main/java/bisq/grpc/BisqGrpcServerMain.java b/grpc/src/main/java/bisq/grpc/BisqGrpcServerMain.java new file mode 100644 index 00000000000..3059931b968 --- /dev/null +++ b/grpc/src/main/java/bisq/grpc/BisqGrpcServerMain.java @@ -0,0 +1,127 @@ +/* + * 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.grpc; + +import bisq.core.CoreApi; +import bisq.core.CoreModule; +import bisq.core.app.BisqExecutable; +import bisq.core.app.BisqHeadlessAppMain; +import bisq.core.app.BisqSetup; + +import bisq.common.UserThread; +import bisq.common.app.AppModule; +import bisq.common.setup.CommonSetup; + +import com.google.common.util.concurrent.ThreadFactoryBuilder; + +import java.util.concurrent.Executors; +import java.util.concurrent.ThreadFactory; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +/** + * Main class to start gRPC server with a headless BisqGrpcApp instance. + */ +public class BisqGrpcServerMain extends BisqHeadlessAppMain implements BisqSetup.BisqSetupListener { + private static BisqGrpcServer bisqGrpcServer; + + public static void main(String[] args) throws Exception { + if (BisqExecutable.setupInitialOptionParser(args)) { + // For some reason the JavaFX launch process results in us losing the thread context class loader: reset it. + // In order to work around a bug in JavaFX 8u25 and below, you must include the following code as the first line of your realMain method: + Thread.currentThread().setContextClassLoader(BisqGrpcServerMain.class.getClassLoader()); + + new BisqGrpcServerMain().execute(args); + } + } + + /////////////////////////////////////////////////////////////////////////////////////////// + // First synchronous execution tasks + /////////////////////////////////////////////////////////////////////////////////////////// + + @Override + protected void configUserThread() { + final ThreadFactory threadFactory = new ThreadFactoryBuilder() + .setNameFormat(this.getClass().getSimpleName()) + .setDaemon(true) + .build(); + UserThread.setExecutor(Executors.newSingleThreadExecutor(threadFactory)); + } + + @Override + protected void launchApplication() { + headlessApp = new BisqGrpcApp(); + CommonSetup.setup(BisqGrpcServerMain.this.headlessApp); + + UserThread.execute(this::onApplicationLaunched); + } + + @Override + protected void onApplicationLaunched() { + super.onApplicationLaunched(); + headlessApp.setGracefulShutDownHandler(this); + } + + @Override + public void onSetupComplete() { + CoreApi coreApi = injector.getInstance(CoreApi.class); + bisqGrpcServer = new BisqGrpcServer(coreApi); + + // If we start headless we need to keep the main thread busy... + try { + bisqGrpcServer.blockUntilShutdown(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + + + /////////////////////////////////////////////////////////////////////////////////////////// + // We continue with a series of synchronous execution tasks + /////////////////////////////////////////////////////////////////////////////////////////// + + @Override + protected AppModule getModule() { + return new CoreModule(bisqEnvironment); + } + + @Override + protected void applyInjector() { + super.applyInjector(); + + headlessApp.setInjector(injector); + } + + @Override + protected void startApplication() { + // We need to be in user thread! We mapped at launchApplication already... + headlessApp.startApplication(); + + // In headless mode we don't have an async behaviour so we trigger the setup by calling onApplicationStarted + onApplicationStarted(); + } + + @Override + protected void onApplicationStarted() { + super.onApplicationStarted(); + + CoreApi coreApi = injector.getInstance(CoreApi.class); + bisqGrpcServer = new BisqGrpcServer(coreApi); + } +} diff --git a/grpc/src/main/java/resources/logback.xml b/grpc/src/main/java/resources/logback.xml new file mode 100644 index 00000000000..ac5e6444ea0 --- /dev/null +++ b/grpc/src/main/java/resources/logback.xml @@ -0,0 +1,16 @@ + + + + + %highlight(%d{MMM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{30}: %msg %xEx%n) + + + + + + + + + + + diff --git a/grpc/src/main/proto/grpc.proto b/grpc/src/main/proto/grpc.proto new file mode 100644 index 00000000000..4ad24c24887 --- /dev/null +++ b/grpc/src/main/proto/grpc.proto @@ -0,0 +1,148 @@ +/* + * 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 . + */ + +syntax = "proto3"; +package io.bisq.protobuffer; + +// FIXME: IntelliJ does not recognize the import but the compiler does +import "pb.proto"; + +option java_package = "bisq.grpc.protobuf"; +option java_multiple_files = true; + +/////////////////////////////////////////////////////////////////////////////////////////// +// Version +/////////////////////////////////////////////////////////////////////////////////////////// + +service GetVersion { + rpc GetVersion (GetVersionRequest) returns (GetVersionReply) { + } +} + +message GetVersionRequest { +} + +message GetVersionReply { + string version = 1; +} + +/////////////////////////////////////////////////////////////////////////////////////////// +// Balance +/////////////////////////////////////////////////////////////////////////////////////////// + +service GetBalance { + rpc GetBalance (GetBalanceRequest) returns (GetBalanceReply) { + } +} + +message GetBalanceRequest { +} + +message GetBalanceReply { + uint64 balance = 1; +} + +/////////////////////////////////////////////////////////////////////////////////////////// +// TradeStatistics +/////////////////////////////////////////////////////////////////////////////////////////// + +service GetTradeStatistics { + rpc GetTradeStatistics (GetTradeStatisticsRequest) returns (GetTradeStatisticsReply) { + } +} + +message GetTradeStatisticsRequest { +} + +// FIXME: IntelliJ does not recognize the imported TradeStatistics2 but the compiler does +message GetTradeStatisticsReply { + repeated TradeStatistics2 TradeStatistics = 1; +} + +/////////////////////////////////////////////////////////////////////////////////////////// +// Offer +/////////////////////////////////////////////////////////////////////////////////////////// + +service GetOffers { + rpc GetOffers (GetOffersRequest) returns (GetOffersReply) { + } +} + +message GetOffersRequest { +} + +// FIXME: IntelliJ does not recognize the imported Offer but the compiler does +message GetOffersReply { + repeated Offer offers = 1; +} + +/////////////////////////////////////////////////////////////////////////////////////////// +// PaymentAccount +/////////////////////////////////////////////////////////////////////////////////////////// + +service GetPaymentAccounts { + rpc GetPaymentAccounts (GetPaymentAccountsRequest) returns (GetPaymentAccountsReply) { + } +} + +message GetPaymentAccountsRequest { +} + +// FIXME: IntelliJ does not recognize the imported PaymentAccount but the compiler does +message GetPaymentAccountsReply { + repeated PaymentAccount paymentAccounts = 1; +} + +/////////////////////////////////////////////////////////////////////////////////////////// +// PlaceOffer +/////////////////////////////////////////////////////////////////////////////////////////// + +service PlaceOffer { + rpc PlaceOffer (PlaceOfferRequest) returns (PlaceOfferReply) { + } +} + +message PlaceOfferRequest { + string currencyCode = 1; + string direction = 2; + uint64 price = 3; + bool useMarketBasedPrice = 4; + double marketPriceMargin = 5; + uint64 amount = 6; + uint64 minAmount = 7; + double buyerSecurityDeposit = 8; + string paymentAccountId = 9; +} + +message PlaceOfferReply { + bool result = 1; +} + +/////////////////////////////////////////////////////////////////////////////////////////// +// StopServer +/////////////////////////////////////////////////////////////////////////////////////////// + +service StopServer { + rpc StopServer (StopServerRequest) returns (StopServerReply) { + } +} + +message StopServerRequest { +} + +message StopServerReply { +} diff --git a/settings.gradle b/settings.gradle index 500b2803c47..960e15d0056 100644 --- a/settings.gradle +++ b/settings.gradle @@ -8,5 +8,6 @@ include 'pricenode' include 'relay' include 'seednode' include 'statsnode' +include 'grpc' rootProject.name = 'bisq' From 65175a7f4fea2127539518ba9fdf4ed646c0459f Mon Sep 17 00:00:00 2001 From: Chris Beams Date: Sat, 21 Dec 2019 10:30:15 +0100 Subject: [PATCH 02/14] Remove --desktopWith{Grpc|Http}Api options for now The previous commit introduces the BisqGrpcServer as a proof of concept, but it is not yet ready for production use. This commit removes the `--desktopWithGrpcApi` option that starts the gRPC server until such time that it is production-ready. This change also removes the `--desktopWithHttpApi` option for starting an HTTP API server. The option has been in place for some time, but it was 'false advertising' in the sense that nothing actually happened if the user specified it, because there is in fact no HTTP API implementation to be started. Note that when the gRPC API option is reintroduced, it will be renamed to `--rpcserver` or similar, following the convention in Bitcoin Core. --- .../java/bisq/core/app/AppOptionKeys.java | 2 -- .../java/bisq/core/app/BisqEnvironment.java | 6 ----- .../java/bisq/core/app/BisqExecutable.java | 10 ------- .../java/bisq/desktop/app/BisqAppMain.java | 26 ++----------------- 4 files changed, 2 insertions(+), 42 deletions(-) diff --git a/core/src/main/java/bisq/core/app/AppOptionKeys.java b/core/src/main/java/bisq/core/app/AppOptionKeys.java index 6c44f7d4f81..b18679cbf0b 100644 --- a/core/src/main/java/bisq/core/app/AppOptionKeys.java +++ b/core/src/main/java/bisq/core/app/AppOptionKeys.java @@ -18,8 +18,6 @@ package bisq.core.app; public class AppOptionKeys { - public static final String DESKTOP_WITH_HTTP_API = "desktopWithHttpApi"; - public static final String DESKTOP_WITH_GRPC_API = "desktopWithGrpcApi"; public static final String APP_NAME_KEY = "appName"; public static final String USER_DATA_DIR_KEY = "userDataDir"; public static final String APP_DATA_DIR_KEY = "appDataDir"; diff --git a/core/src/main/java/bisq/core/app/BisqEnvironment.java b/core/src/main/java/bisq/core/app/BisqEnvironment.java index ddebb407ae1..de8decf27dd 100644 --- a/core/src/main/java/bisq/core/app/BisqEnvironment.java +++ b/core/src/main/java/bisq/core/app/BisqEnvironment.java @@ -186,8 +186,6 @@ public static boolean isDaoActivated(Environment environment) { @Setter protected boolean isBitcoinLocalhostNodeRunning; @Getter - protected String desktopWithHttpApi, desktopWithGrpcApi; - @Getter protected List bannedSeedNodes, bannedBtcNodes, bannedPriceRelayNodes; protected final String btcNodes, seedNodes, ignoreDevMsg, useDevPrivilegeKeys, useDevMode, useTorForBtc, rpcUser, rpcPassword, @@ -219,8 +217,6 @@ public BisqEnvironment(PropertySource commandLineProperties) { appDataDir = getProperty(commandLineProperties, AppOptionKeys.APP_DATA_DIR_KEY, appDataDir(userDataDir, appName)); staticAppDataDir = appDataDir; - desktopWithHttpApi = getProperty(commandLineProperties, AppOptionKeys.DESKTOP_WITH_HTTP_API, "false"); - desktopWithGrpcApi = getProperty(commandLineProperties, AppOptionKeys.DESKTOP_WITH_GRPC_API, "false"); ignoreDevMsg = getProperty(commandLineProperties, AppOptionKeys.IGNORE_DEV_MSG_KEY, ""); useDevPrivilegeKeys = getProperty(commandLineProperties, AppOptionKeys.USE_DEV_PRIVILEGE_KEYS, ""); referralId = getProperty(commandLineProperties, AppOptionKeys.REFERRAL_ID, ""); @@ -398,8 +394,6 @@ private PropertySource defaultProperties() { setProperty(NetworkOptionKeys.SEND_MSG_THROTTLE_SLEEP, sendMsgThrottleSleep); setProperty(AppOptionKeys.APP_DATA_DIR_KEY, appDataDir); - setProperty(AppOptionKeys.DESKTOP_WITH_HTTP_API, desktopWithHttpApi); - setProperty(AppOptionKeys.DESKTOP_WITH_GRPC_API, desktopWithGrpcApi); setProperty(AppOptionKeys.IGNORE_DEV_MSG_KEY, ignoreDevMsg); setProperty(AppOptionKeys.USE_DEV_PRIVILEGE_KEYS, useDevPrivilegeKeys); setProperty(AppOptionKeys.REFERRAL_ID, referralId); diff --git a/core/src/main/java/bisq/core/app/BisqExecutable.java b/core/src/main/java/bisq/core/app/BisqExecutable.java index 6a8be7955e4..8dd905bc06e 100644 --- a/core/src/main/java/bisq/core/app/BisqExecutable.java +++ b/core/src/main/java/bisq/core/app/BisqExecutable.java @@ -446,16 +446,6 @@ protected void customizeOptionParsing(OptionParser parser) { .withRequiredArg() .ofType(boolean.class); - parser.accepts(AppOptionKeys.DESKTOP_WITH_HTTP_API, - format("If set to true Bisq Desktop starts with Http API (default: %s)", "false")) - .withRequiredArg() - .ofType(boolean.class); - - parser.accepts(AppOptionKeys.DESKTOP_WITH_GRPC_API, - format("If set to true Bisq Desktop starts with gRPC API (default: %s)", "false")) - .withRequiredArg() - .ofType(boolean.class); - parser.accepts(AppOptionKeys.USE_DEV_PRIVILEGE_KEYS, format("If that is true all the privileged features which requires a private key " + "to enable it are overridden by a dev key pair (This is for developers only!) (default: %s)", "false")) diff --git a/desktop/src/main/java/bisq/desktop/app/BisqAppMain.java b/desktop/src/main/java/bisq/desktop/app/BisqAppMain.java index cccaf5a63b4..7f63a3ef696 100644 --- a/desktop/src/main/java/bisq/desktop/app/BisqAppMain.java +++ b/desktop/src/main/java/bisq/desktop/app/BisqAppMain.java @@ -21,7 +21,6 @@ import bisq.desktop.common.view.guice.InjectorViewFactory; import bisq.desktop.setup.DesktopPersistedDataHost; -import bisq.core.CoreApi; import bisq.core.app.BisqExecutable; import bisq.common.UserThread; @@ -37,12 +36,6 @@ import lombok.extern.slf4j.Slf4j; -import javax.annotation.Nullable; - - - -import bisq.grpc.BisqGrpcServer; - @Slf4j public class BisqAppMain extends BisqExecutable { private BisqApp application; @@ -51,11 +44,6 @@ public BisqAppMain() { super("Bisq Desktop", "bisq-desktop", Version.VERSION); } - /* @Nullable - private BisqHttpApiServer bisqHttpApiServer;*/ - @Nullable - private BisqGrpcServer bisqGrpcServer; - public static void main(String[] args) throws Exception { if (BisqExecutable.setupInitialOptionParser(args)) { // For some reason the JavaFX launch process results in us losing the thread context class loader: reset it. @@ -142,21 +130,11 @@ protected void startApplication() { protected void onApplicationStarted() { super.onApplicationStarted(); - /* if (runWithHttpApi()) { - bisqHttpApiServer = new BisqHttpApiServer(); - }*/ - + /* if (runWithGrpcApi()) { CoreApi coreApi = injector.getInstance(CoreApi.class); bisqGrpcServer = new BisqGrpcServer(coreApi); } - } - - private boolean runWithHttpApi() { - return bisqEnvironment.getDesktopWithHttpApi().toLowerCase().equals("true"); - } - - private boolean runWithGrpcApi() { - return bisqEnvironment.getDesktopWithGrpcApi().toLowerCase().equals("true"); + */ } } From 7595387c8e59a59e34fcf2818cfd220e083a4b75 Mon Sep 17 00:00:00 2001 From: Chris Beams Date: Fri, 17 Jan 2020 12:40:33 +0100 Subject: [PATCH 03/14] Fix code quality issues Per Codacy report at https://app.codacy.com/gh/bisq-network/bisq/pullRequest?prid=4835063 --- grpc/src/main/java/bisq/grpc/BisqGrpcClient.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/grpc/src/main/java/bisq/grpc/BisqGrpcClient.java b/grpc/src/main/java/bisq/grpc/BisqGrpcClient.java index d3d698cf791..489946b2f7d 100644 --- a/grpc/src/main/java/bisq/grpc/BisqGrpcClient.java +++ b/grpc/src/main/java/bisq/grpc/BisqGrpcClient.java @@ -35,6 +35,7 @@ import lombok.extern.slf4j.Slf4j; import static com.google.common.base.Preconditions.checkArgument; +import static java.lang.String.format; @@ -65,7 +66,6 @@ */ @Slf4j public class BisqGrpcClient { - private static BisqGrpcClient instance; private final ManagedChannel channel; private final GetVersionGrpc.GetVersionBlockingStub getVersionStub; @@ -76,10 +76,9 @@ public class BisqGrpcClient { private final GetPaymentAccountsGrpc.GetPaymentAccountsBlockingStub getPaymentAccountsStub; private final PlaceOfferGrpc.PlaceOfferBlockingStub placeOfferBlockingStub; private final CorePersistenceProtoResolver corePersistenceProtoResolver; - private final CoreNetworkProtoResolver coreNetworkProtoResolver; public static void main(String[] args) throws Exception { - instance = new BisqGrpcClient("localhost", 8888); + new BisqGrpcClient("localhost", 8888); } private BisqGrpcClient(String host, int port) { @@ -176,6 +175,8 @@ private BisqGrpcClient(String host, int port) { stopServer(); result = "Server stopped"; break; + default: + result = format("Unknown command '%s'", command); } // First response is rather slow (300 ms) but following responses are fast (3-5 ms). @@ -199,7 +200,7 @@ private BisqGrpcClient(ManagedChannel channel) { placeOfferBlockingStub = PlaceOfferGrpc.newBlockingStub(channel); stopServerStub = StopServerGrpc.newBlockingStub(channel); - coreNetworkProtoResolver = new CoreNetworkProtoResolver(Clock.systemDefaultZone()); + CoreNetworkProtoResolver coreNetworkProtoResolver = new CoreNetworkProtoResolver(Clock.systemDefaultZone()); //TODO corePersistenceProtoResolver = new CorePersistenceProtoResolver(null, coreNetworkProtoResolver, null, null); } From 8b30c22d6ee5a9f20c10ab3aa68343c4b79da742 Mon Sep 17 00:00:00 2001 From: Chris Beams Date: Thu, 21 Nov 2019 21:31:39 +0100 Subject: [PATCH 04/14] Move bisq.core{=>.app}.CoreModule There are two structural / organizational reasons for this move: 1. References from one package to another should always be upward or lateral, never downward, as the latter causes package cycles (aka 'tangles') which damage the suppleness and understandability of a large codebase. Prior to this change the high-level bisq.core.CoreModule class imported many classes from child packages like bisq.core.{btc,dao,user,util}, etc. By moving CoreModule down into the '.app' package, it can reference all these other packages as siblings instead of doing so as a parent. 2. the bisq.core.desktop and bisq.core.app packages are the only locations that reference the CoreModule class. By moving the class into bisq.core.app, greater cohesion is acheived, again making the codebase that much easier to read and understand. --- core/src/main/java/bisq/core/app/BisqHeadlessAppMain.java | 2 -- core/src/main/java/bisq/core/{ => app}/CoreModule.java | 4 +--- desktop/src/main/java/bisq/desktop/app/BisqAppModule.java | 2 +- grpc/src/main/java/bisq/grpc/BisqGrpcServerMain.java | 2 +- 4 files changed, 3 insertions(+), 7 deletions(-) rename core/src/main/java/bisq/core/{ => app}/CoreModule.java (98%) diff --git a/core/src/main/java/bisq/core/app/BisqHeadlessAppMain.java b/core/src/main/java/bisq/core/app/BisqHeadlessAppMain.java index 09e9f451088..e3fe211572f 100644 --- a/core/src/main/java/bisq/core/app/BisqHeadlessAppMain.java +++ b/core/src/main/java/bisq/core/app/BisqHeadlessAppMain.java @@ -17,8 +17,6 @@ package bisq.core.app; -import bisq.core.CoreModule; - import bisq.common.UserThread; import bisq.common.app.AppModule; import bisq.common.app.Version; diff --git a/core/src/main/java/bisq/core/CoreModule.java b/core/src/main/java/bisq/core/app/CoreModule.java similarity index 98% rename from core/src/main/java/bisq/core/CoreModule.java rename to core/src/main/java/bisq/core/app/CoreModule.java index 4d921e6501e..431dc1555e3 100644 --- a/core/src/main/java/bisq/core/CoreModule.java +++ b/core/src/main/java/bisq/core/app/CoreModule.java @@ -15,11 +15,9 @@ * along with Bisq. If not, see . */ -package bisq.core; +package bisq.core.app; import bisq.core.alert.AlertModule; -import bisq.core.app.AppOptionKeys; -import bisq.core.app.BisqEnvironment; import bisq.core.btc.BitcoinModule; import bisq.core.dao.DaoModule; import bisq.core.filter.FilterModule; diff --git a/desktop/src/main/java/bisq/desktop/app/BisqAppModule.java b/desktop/src/main/java/bisq/desktop/app/BisqAppModule.java index 75c389288e3..942c49a718b 100644 --- a/desktop/src/main/java/bisq/desktop/app/BisqAppModule.java +++ b/desktop/src/main/java/bisq/desktop/app/BisqAppModule.java @@ -19,7 +19,7 @@ import bisq.desktop.DesktopModule; -import bisq.core.CoreModule; +import bisq.core.app.CoreModule; import bisq.common.app.AppModule; diff --git a/grpc/src/main/java/bisq/grpc/BisqGrpcServerMain.java b/grpc/src/main/java/bisq/grpc/BisqGrpcServerMain.java index 3059931b968..7776686a7bb 100644 --- a/grpc/src/main/java/bisq/grpc/BisqGrpcServerMain.java +++ b/grpc/src/main/java/bisq/grpc/BisqGrpcServerMain.java @@ -18,10 +18,10 @@ package bisq.grpc; import bisq.core.CoreApi; -import bisq.core.CoreModule; import bisq.core.app.BisqExecutable; import bisq.core.app.BisqHeadlessAppMain; import bisq.core.app.BisqSetup; +import bisq.core.app.CoreModule; import bisq.common.UserThread; import bisq.common.app.AppModule; From 29698fd58a6b7995971a1c0ae9898a4a5e7634c1 Mon Sep 17 00:00:00 2001 From: Chris Beams Date: Wed, 20 Nov 2019 21:04:34 +0100 Subject: [PATCH 05/14] Introduce 'cli' subproject This change stubs out the `bisq-cli` utility with a placeholder main method, such that the following now works: $ gradle :cli:build $ ./bisq-cli Hello, World! --- build.gradle | 15 ++++++++++++--- cli/src/main/java/bisq/cli/app/BisqCliMain.java | 8 ++++++++ settings.gradle | 1 + 3 files changed, 21 insertions(+), 3 deletions(-) create mode 100644 cli/src/main/java/bisq/cli/app/BisqCliMain.java diff --git a/build.gradle b/build.gradle index dff1addf2f0..b74fdcfcffb 100644 --- a/build.gradle +++ b/build.gradle @@ -89,13 +89,14 @@ configure(subprojects) { } -configure([project(':desktop'), +configure([project(':cli'), + project(':desktop'), + project(':grpc'), project(':monitor'), project(':relay'), project(':seednode'), project(':statsnode'), - project(':pricenode'), - project(':grpc')]) { + project(':pricenode')]) { apply plugin: 'application' @@ -271,6 +272,14 @@ configure(project(':core')) { } } +configure(project(':cli')) { + mainClassName = 'bisq.cli.app.BisqCliMain' + + dependencies { + compile project(':core') + } +} + configure(project(':desktop')) { apply plugin: 'com.github.johnrengelman.shadow' apply plugin: 'witness' diff --git a/cli/src/main/java/bisq/cli/app/BisqCliMain.java b/cli/src/main/java/bisq/cli/app/BisqCliMain.java new file mode 100644 index 00000000000..54a57041516 --- /dev/null +++ b/cli/src/main/java/bisq/cli/app/BisqCliMain.java @@ -0,0 +1,8 @@ +package bisq.cli.app; + +public class BisqCliMain { + + public static void main(String[] args) { + System.out.println("Hello, World!"); + } +} diff --git a/settings.gradle b/settings.gradle index 960e15d0056..14a57ab1464 100644 --- a/settings.gradle +++ b/settings.gradle @@ -2,6 +2,7 @@ include 'assets' include 'common' include 'p2p' include 'core' +include 'cli' include 'desktop' include 'monitor' include 'pricenode' From 7a718f0ed58536191858902dd9378a721b8c48c0 Mon Sep 17 00:00:00 2001 From: Chris Beams Date: Thu, 21 Nov 2019 07:48:25 +0100 Subject: [PATCH 06/14] Move grpc generation from :grpc to :core Such that :grpc (soon to be renamed to :daemon), :cli and :desktop can access these types. --- build.gradle | 111 ++++++++++++----------- {grpc => core}/src/main/proto/grpc.proto | 0 2 files changed, 58 insertions(+), 53 deletions(-) rename {grpc => core}/src/main/proto/grpc.proto (100%) diff --git a/build.gradle b/build.gradle index b74fdcfcffb..740a746be2e 100644 --- a/build.gradle +++ b/build.gradle @@ -230,6 +230,28 @@ configure(project(':p2p')) { configure(project(':core')) { + apply plugin: 'com.google.protobuf' + + // FIXME we dont want to have one src dir inside the other.... + sourceSets.main.java.srcDir "$buildDir/generated/source/proto/main" + sourceSets.main.java.srcDir "$buildDir/generated/source/proto/main/java" + + protobuf { + protoc { + artifact = "com.google.protobuf:protoc:$protobufVersion" + } + plugins { + grpc { + artifact = "io.grpc:protoc-gen-grpc-java:$grpcVersion" + } + } + generateProtoTasks { + all()*.plugins { + grpc {} + } + } + } + dependencies { compile project(':assets') compile project(':p2p') @@ -259,6 +281,40 @@ configure(project(':core')) { compileOnly "org.projectlombok:lombok:$lombokVersion" annotationProcessor "org.projectlombok:lombok:$lombokVersion" + compile "com.google.protobuf:protobuf-java:$protobufVersion" + compile "com.google.api.grpc:proto-google-common-protos:$commonProtosVersion" + + // FIXME Not clear which of the following libs have a newer version of guava which is not compatible with ours + compile ("io.grpc:grpc-alts:$grpcVersion") { + exclude(module: 'guava') + } + + compile ("io.grpc:grpc-netty:$grpcVersion") { + exclude(module: 'guava') + } + + compile ("io.grpc:grpc-protobuf:$grpcVersion") { + exclude(module: 'guava') + } + + compile ("io.grpc:grpc-stub:$grpcVersion") { + exclude(module: 'guava') + } + + // Used for TLS in HelloWorldServerTls + compile "io.netty:netty-tcnative-boringssl-static:${nettyTcNativeVersion}" + + compileOnly "org.projectlombok:lombok:$lombokVersion" + compileOnly "javax.annotation:javax.annotation-api:1.2" + annotationProcessor "org.projectlombok:lombok:$lombokVersion" + + testCompile "io.grpc:grpc-testing:${grpcVersion}" + testCompile "org.mockito:mockito-core:$mockitoVersion" + testCompile "org.springframework:spring-test:$springVersion" + testCompile "com.natpryce:make-it-easy:$easyVersion" + testCompileOnly "org.projectlombok:lombok:$lombokVersion" + testAnnotationProcessor "org.projectlombok:lombok:$lombokVersion" + testCompile "org.mockito:mockito-core:$mockitoVersion" testCompile "org.springframework:spring-test:$springVersion" testCompile "com.natpryce:make-it-easy:$easyVersion" @@ -277,6 +333,8 @@ configure(project(':cli')) { dependencies { compile project(':core') + compileOnly "org.projectlombok:lombok:$lombokVersion" + annotationProcessor "org.projectlombok:lombok:$lombokVersion" } } @@ -417,65 +475,12 @@ configure(project(':statsnode')) { } configure(project(':grpc')) { - apply plugin: 'com.google.protobuf' - mainClassName = 'bisq.grpc.BisqGrpcServerMain' - // FIXME we dont want to have one src dir inside the other.... - sourceSets.main.java.srcDir "$buildDir/generated/source/proto/main" - sourceSets.main.java.srcDir "$buildDir/generated/source/proto/main/java" - - protobuf { - protoc { - artifact = "com.google.protobuf:protoc:$protobufVersion" - } - plugins { - grpc { - artifact = "io.grpc:protoc-gen-grpc-java:$grpcVersion" - } - } - generateProtoTasks { - all()*.plugins { - grpc {} - } - } - } - dependencies { compile project(':core') - compile "com.google.protobuf:protobuf-java:$protobufVersion" - compile "com.google.api.grpc:proto-google-common-protos:$commonProtosVersion" - - // FIXME Not clear which of the following libs have a newer version of guava which is not compatible with ours - compile ("io.grpc:grpc-alts:$grpcVersion") { - exclude(module: 'guava') - } - - compile ("io.grpc:grpc-netty:$grpcVersion") { - exclude(module: 'guava') - } - - - compile ("io.grpc:grpc-protobuf:$grpcVersion") { - exclude(module: 'guava') - } - - compile ("io.grpc:grpc-stub:$grpcVersion") { - exclude(module: 'guava') - } - - // Used for TLS in HelloWorldServerTls - compile "io.netty:netty-tcnative-boringssl-static:${nettyTcNativeVersion}" - compileOnly "org.projectlombok:lombok:$lombokVersion" compileOnly "javax.annotation:javax.annotation-api:1.2" annotationProcessor "org.projectlombok:lombok:$lombokVersion" - - testCompile "io.grpc:grpc-testing:${grpcVersion}" - testCompile "org.mockito:mockito-core:$mockitoVersion" - testCompile "org.springframework:spring-test:$springVersion" - testCompile "com.natpryce:make-it-easy:$easyVersion" - testCompileOnly "org.projectlombok:lombok:$lombokVersion" - testAnnotationProcessor "org.projectlombok:lombok:$lombokVersion" } } diff --git a/grpc/src/main/proto/grpc.proto b/core/src/main/proto/grpc.proto similarity index 100% rename from grpc/src/main/proto/grpc.proto rename to core/src/main/proto/grpc.proto From 07d98a3aba96b3224c9c19070fe7ee690c941682 Mon Sep 17 00:00:00 2001 From: Chris Beams Date: Thu, 21 Nov 2019 12:32:00 +0100 Subject: [PATCH 07/14] Move bisq.{grpc.BisqGrpcClient=>cli.BisqCliMain} This change replaces the previous "Hello, World!" :cli main stub with the contents of the BisqGrpcClient as originally implemented in :grpc, such that the following now works: $ gradle build $ ./bisq-daemon # in first terminal $ ./bisq-cli # in second terminal getVersion # user input to stdin 1.2.3 # rpc response getBalance # user input to stdin 0.00 # rpc response ... Or for a user experience closer to where things are headed: $ echo getVersion | ./bisq-cli 1.2.3 Note that processing the above command is currently far too slow: $ time echo getVersion | ./bisq-cli 1.2.3 real 0m1.634s # ouch user 0m1.746s sys 0m0.180s Subsequent commits will work to bring this time down to a minimum. Note: Includes the code quality changes originally made to BisqGrpcClient in commit 7595387. --- .../main/java/bisq/cli/app/BisqCliMain.java | 294 ++++++++++++++++- .../main/java/bisq/grpc/BisqGrpcClient.java | 298 ------------------ 2 files changed, 292 insertions(+), 300 deletions(-) delete mode 100644 grpc/src/main/java/bisq/grpc/BisqGrpcClient.java diff --git a/cli/src/main/java/bisq/cli/app/BisqCliMain.java b/cli/src/main/java/bisq/cli/app/BisqCliMain.java index 54a57041516..dbc78c641d6 100644 --- a/cli/src/main/java/bisq/cli/app/BisqCliMain.java +++ b/cli/src/main/java/bisq/cli/app/BisqCliMain.java @@ -1,8 +1,298 @@ +/* + * 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.cli.app; +import bisq.core.payment.PaymentAccount; +import bisq.core.proto.network.CoreNetworkProtoResolver; +import bisq.core.proto.persistable.CorePersistenceProtoResolver; + +import org.bitcoinj.core.Coin; + +import java.time.Clock; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Scanner; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; + +import lombok.extern.slf4j.Slf4j; + +import static com.google.common.base.Preconditions.checkArgument; +import static java.lang.String.format; + + + +import bisq.grpc.protobuf.GetBalanceGrpc; +import bisq.grpc.protobuf.GetBalanceRequest; +import bisq.grpc.protobuf.GetOffersGrpc; +import bisq.grpc.protobuf.GetOffersRequest; +import bisq.grpc.protobuf.GetPaymentAccountsGrpc; +import bisq.grpc.protobuf.GetPaymentAccountsRequest; +import bisq.grpc.protobuf.GetTradeStatisticsGrpc; +import bisq.grpc.protobuf.GetTradeStatisticsRequest; +import bisq.grpc.protobuf.GetVersionGrpc; +import bisq.grpc.protobuf.GetVersionRequest; +import bisq.grpc.protobuf.PlaceOfferGrpc; +import bisq.grpc.protobuf.PlaceOfferRequest; +import bisq.grpc.protobuf.StopServerGrpc; +import bisq.grpc.protobuf.StopServerRequest; +import io.grpc.ManagedChannel; +import io.grpc.ManagedChannelBuilder; +import io.grpc.StatusRuntimeException; + +/** + * gRPC client. + * + * FIXME We get warning 'DEBUG io.grpc.netty.shaded.io.netty.util.internal.PlatformDependent0 - direct buffer constructor: unavailable + * java.lang.UnsupportedOperationException: Reflective setAccessible(true) disabled' which is + * related to Java 10 changes. Requests are working but we should find out why we get that warning + */ +@Slf4j public class BisqCliMain { - public static void main(String[] args) { - System.out.println("Hello, World!"); + private final ManagedChannel channel; + private final GetVersionGrpc.GetVersionBlockingStub getVersionStub; + private final GetBalanceGrpc.GetBalanceBlockingStub getBalanceStub; + private final StopServerGrpc.StopServerBlockingStub stopServerStub; + private final GetTradeStatisticsGrpc.GetTradeStatisticsBlockingStub getTradeStatisticsStub; + private final GetOffersGrpc.GetOffersBlockingStub getOffersStub; + private final GetPaymentAccountsGrpc.GetPaymentAccountsBlockingStub getPaymentAccountsStub; + private final PlaceOfferGrpc.PlaceOfferBlockingStub placeOfferBlockingStub; + private final CorePersistenceProtoResolver corePersistenceProtoResolver; + + public static void main(String[] args) throws Exception { + new BisqCliMain("localhost", 8888); + } + + private BisqCliMain(String host, int port) { + this(ManagedChannelBuilder.forAddress(host, port) + // Channels are secure by default (via SSL/TLS). For the example we disable TLS to avoid + // needing certificates. + .usePlaintext(true).build()); + + // Simple input scanner + // TODO use some more sophisticated input processing with validation.... + try (Scanner scanner = new Scanner(System.in);) { + while (true) { + long startTs = System.currentTimeMillis(); + + String[] tokens = scanner.nextLine().split(" "); + if (tokens.length == 0) { + return; + } + String command = tokens[0]; + List params = new ArrayList<>(); + if (tokens.length > 1) { + params.addAll(Arrays.asList(tokens)); + params.remove(0); + } + String result = ""; + + switch (command) { + case "getVersion": + result = getVersion(); + break; + case "getBalance": + result = Coin.valueOf(getBalance()).toFriendlyString(); + break; + case "getTradeStatistics": + List tradeStatistics = getTradeStatistics().stream() + .map(bisq.core.trade.statistics.TradeStatistics2::fromProto) + .collect(Collectors.toList()); + + result = tradeStatistics.toString(); + break; + case "getOffers": + List offers = getOffers().stream() + .map(bisq.core.offer.Offer::fromProto) + .collect(Collectors.toList()); + result = offers.toString(); + break; + case "getPaymentAccounts": + List paymentAccounts = getPaymentAccounts().stream() + .map(proto -> PaymentAccount.fromProto(proto, corePersistenceProtoResolver)) + .collect(Collectors.toList()); + result = paymentAccounts.toString(); + break; + case "placeOffer": + // test input: placeOffer CNY BUY 750000000 true -0.2251 1000000 500000 0.12 5a972121-c30a-4b0e-b519-b17b63795d16 + // payment accountId and currency need to be adopted + + // We expect 9 params + // TODO add basic input validation + try { + checkArgument(params.size() == 9); + String currencyCode = params.get(0); + String directionAsString = params.get(1); + long priceAsLong = Long.parseLong(params.get(2)); + boolean useMarketBasedPrice = Boolean.parseBoolean(params.get(3)); + double marketPriceMargin = Double.parseDouble(params.get(4)); + long amountAsLong = Long.parseLong(params.get(5)); + long minAmountAsLong = Long.parseLong(params.get(6)); + double buyerSecurityDeposit = Double.parseDouble(params.get(7)); + String paymentAccountId = params.get(8); + boolean success = placeOffer(currencyCode, + directionAsString, + priceAsLong, + useMarketBasedPrice, + marketPriceMargin, + amountAsLong, + minAmountAsLong, + buyerSecurityDeposit, + paymentAccountId); + result = String.valueOf(success); + break; + } catch (Throwable t) { + log.error(t.toString(), t); + break; + } + case "stop": + result = "Shut down client"; + try { + shutdown(); + } catch (InterruptedException e) { + log.error(e.toString(), e); + } + break; + case "stopServer": + stopServer(); + result = "Server stopped"; + break; + default: + result = format("Unknown command '%s'", command); + } + + // First response is rather slow (300 ms) but following responses are fast (3-5 ms). + log.info("Request took: {} ms", System.currentTimeMillis() - startTs); + log.info(result); + } + } + } + + /** + * Construct client for accessing server using the existing channel. + */ + private BisqCliMain(ManagedChannel channel) { + this.channel = channel; + + getVersionStub = GetVersionGrpc.newBlockingStub(channel); + getBalanceStub = GetBalanceGrpc.newBlockingStub(channel); + getTradeStatisticsStub = GetTradeStatisticsGrpc.newBlockingStub(channel); + getOffersStub = GetOffersGrpc.newBlockingStub(channel); + getPaymentAccountsStub = GetPaymentAccountsGrpc.newBlockingStub(channel); + placeOfferBlockingStub = PlaceOfferGrpc.newBlockingStub(channel); + stopServerStub = StopServerGrpc.newBlockingStub(channel); + + CoreNetworkProtoResolver coreNetworkProtoResolver = new CoreNetworkProtoResolver(Clock.systemDefaultZone()); + //TODO + corePersistenceProtoResolver = new CorePersistenceProtoResolver(null, coreNetworkProtoResolver, null, null); + } + + private String getVersion() { + GetVersionRequest request = GetVersionRequest.newBuilder().build(); + try { + return getVersionStub.getVersion(request).getVersion(); + } catch (StatusRuntimeException e) { + return "RPC failed: " + e.getStatus(); + } + } + + private long getBalance() { + GetBalanceRequest request = GetBalanceRequest.newBuilder().build(); + try { + return getBalanceStub.getBalance(request).getBalance(); + } catch (StatusRuntimeException e) { + log.warn("RPC failed: {}", e.getStatus()); + return -1; + } + } + + private List getTradeStatistics() { + GetTradeStatisticsRequest request = GetTradeStatisticsRequest.newBuilder().build(); + try { + return getTradeStatisticsStub.getTradeStatistics(request).getTradeStatisticsList(); + } catch (StatusRuntimeException e) { + log.warn("RPC failed: {}", e.getStatus()); + return null; + } + } + + private List getOffers() { + GetOffersRequest request = GetOffersRequest.newBuilder().build(); + try { + return getOffersStub.getOffers(request).getOffersList(); + } catch (StatusRuntimeException e) { + log.warn("RPC failed: {}", e.getStatus()); + return null; + } + } + + private List getPaymentAccounts() { + GetPaymentAccountsRequest request = GetPaymentAccountsRequest.newBuilder().build(); + try { + return getPaymentAccountsStub.getPaymentAccounts(request).getPaymentAccountsList(); + } catch (StatusRuntimeException e) { + log.warn("RPC failed: {}", e.getStatus()); + return null; + } + } + + private boolean placeOffer(String currencyCode, + String directionAsString, + long priceAsLong, + boolean useMarketBasedPrice, + double marketPriceMargin, + long amountAsLong, + long minAmountAsLong, + double buyerSecurityDeposit, + String paymentAccountId) { + PlaceOfferRequest request = PlaceOfferRequest.newBuilder() + .setCurrencyCode(currencyCode) + .setDirection(directionAsString) + .setPrice(priceAsLong) + .setUseMarketBasedPrice(useMarketBasedPrice) + .setMarketPriceMargin(marketPriceMargin) + .setAmount(amountAsLong) + .setMinAmount(minAmountAsLong) + .setBuyerSecurityDeposit(buyerSecurityDeposit) + .setPaymentAccountId(paymentAccountId) + .build(); + try { + return placeOfferBlockingStub.placeOffer(request).getResult(); + } catch (StatusRuntimeException e) { + log.warn("RPC failed: {}", e.getStatus()); + return false; + } + } + + private void stopServer() { + StopServerRequest request = StopServerRequest.newBuilder().build(); + try { + stopServerStub.stopServer(request); + } catch (StatusRuntimeException e) { + log.warn("RPC failed: {}", e.getStatus()); + } + } + + private void shutdown() throws InterruptedException { + channel.shutdown().awaitTermination(1, TimeUnit.SECONDS); + System.exit(0); } } diff --git a/grpc/src/main/java/bisq/grpc/BisqGrpcClient.java b/grpc/src/main/java/bisq/grpc/BisqGrpcClient.java deleted file mode 100644 index 489946b2f7d..00000000000 --- a/grpc/src/main/java/bisq/grpc/BisqGrpcClient.java +++ /dev/null @@ -1,298 +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.grpc; - -import bisq.core.payment.PaymentAccount; -import bisq.core.proto.network.CoreNetworkProtoResolver; -import bisq.core.proto.persistable.CorePersistenceProtoResolver; - -import org.bitcoinj.core.Coin; - -import java.time.Clock; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Scanner; -import java.util.concurrent.TimeUnit; -import java.util.stream.Collectors; - -import lombok.extern.slf4j.Slf4j; - -import static com.google.common.base.Preconditions.checkArgument; -import static java.lang.String.format; - - - -import bisq.grpc.protobuf.GetBalanceGrpc; -import bisq.grpc.protobuf.GetBalanceRequest; -import bisq.grpc.protobuf.GetOffersGrpc; -import bisq.grpc.protobuf.GetOffersRequest; -import bisq.grpc.protobuf.GetPaymentAccountsGrpc; -import bisq.grpc.protobuf.GetPaymentAccountsRequest; -import bisq.grpc.protobuf.GetTradeStatisticsGrpc; -import bisq.grpc.protobuf.GetTradeStatisticsRequest; -import bisq.grpc.protobuf.GetVersionGrpc; -import bisq.grpc.protobuf.GetVersionRequest; -import bisq.grpc.protobuf.PlaceOfferGrpc; -import bisq.grpc.protobuf.PlaceOfferRequest; -import bisq.grpc.protobuf.StopServerGrpc; -import bisq.grpc.protobuf.StopServerRequest; -import io.grpc.ManagedChannel; -import io.grpc.ManagedChannelBuilder; -import io.grpc.StatusRuntimeException; - -/** - * gRPC client. - * - * FIXME We get warning 'DEBUG io.grpc.netty.shaded.io.netty.util.internal.PlatformDependent0 - direct buffer constructor: unavailable - * java.lang.UnsupportedOperationException: Reflective setAccessible(true) disabled' which is - * related to Java 10 changes. Requests are working but we should find out why we get that warning - */ -@Slf4j -public class BisqGrpcClient { - - private final ManagedChannel channel; - private final GetVersionGrpc.GetVersionBlockingStub getVersionStub; - private final GetBalanceGrpc.GetBalanceBlockingStub getBalanceStub; - private final StopServerGrpc.StopServerBlockingStub stopServerStub; - private final GetTradeStatisticsGrpc.GetTradeStatisticsBlockingStub getTradeStatisticsStub; - private final GetOffersGrpc.GetOffersBlockingStub getOffersStub; - private final GetPaymentAccountsGrpc.GetPaymentAccountsBlockingStub getPaymentAccountsStub; - private final PlaceOfferGrpc.PlaceOfferBlockingStub placeOfferBlockingStub; - private final CorePersistenceProtoResolver corePersistenceProtoResolver; - - public static void main(String[] args) throws Exception { - new BisqGrpcClient("localhost", 8888); - } - - private BisqGrpcClient(String host, int port) { - this(ManagedChannelBuilder.forAddress(host, port) - // Channels are secure by default (via SSL/TLS). For the example we disable TLS to avoid - // needing certificates. - .usePlaintext(true).build()); - - // Simple input scanner - // TODO use some more sophisticated input processing with validation.... - try (Scanner scanner = new Scanner(System.in);) { - while (true) { - long startTs = System.currentTimeMillis(); - - String[] tokens = scanner.nextLine().split(" "); - if (tokens.length == 0) { - return; - } - String command = tokens[0]; - List params = new ArrayList<>(); - if (tokens.length > 1) { - params.addAll(Arrays.asList(tokens)); - params.remove(0); - } - String result = ""; - - switch (command) { - case "getVersion": - result = getVersion(); - break; - case "getBalance": - result = Coin.valueOf(getBalance()).toFriendlyString(); - break; - case "getTradeStatistics": - List tradeStatistics = getTradeStatistics().stream() - .map(bisq.core.trade.statistics.TradeStatistics2::fromProto) - .collect(Collectors.toList()); - - result = tradeStatistics.toString(); - break; - case "getOffers": - List offers = getOffers().stream() - .map(bisq.core.offer.Offer::fromProto) - .collect(Collectors.toList()); - result = offers.toString(); - break; - case "getPaymentAccounts": - List paymentAccounts = getPaymentAccounts().stream() - .map(proto -> PaymentAccount.fromProto(proto, corePersistenceProtoResolver)) - .collect(Collectors.toList()); - result = paymentAccounts.toString(); - break; - case "placeOffer": - // test input: placeOffer CNY BUY 750000000 true -0.2251 1000000 500000 0.12 5a972121-c30a-4b0e-b519-b17b63795d16 - // payment accountId and currency need to be adopted - - // We expect 9 params - // TODO add basic input validation - try { - checkArgument(params.size() == 9); - String currencyCode = params.get(0); - String directionAsString = params.get(1); - long priceAsLong = Long.parseLong(params.get(2)); - boolean useMarketBasedPrice = Boolean.parseBoolean(params.get(3)); - double marketPriceMargin = Double.parseDouble(params.get(4)); - long amountAsLong = Long.parseLong(params.get(5)); - long minAmountAsLong = Long.parseLong(params.get(6)); - double buyerSecurityDeposit = Double.parseDouble(params.get(7)); - String paymentAccountId = params.get(8); - boolean success = placeOffer(currencyCode, - directionAsString, - priceAsLong, - useMarketBasedPrice, - marketPriceMargin, - amountAsLong, - minAmountAsLong, - buyerSecurityDeposit, - paymentAccountId); - result = String.valueOf(success); - break; - } catch (Throwable t) { - log.error(t.toString(), t); - break; - } - case "stop": - result = "Shut down client"; - try { - shutdown(); - } catch (InterruptedException e) { - log.error(e.toString(), e); - } - break; - case "stopServer": - stopServer(); - result = "Server stopped"; - break; - default: - result = format("Unknown command '%s'", command); - } - - // First response is rather slow (300 ms) but following responses are fast (3-5 ms). - log.info("Request took: {} ms", System.currentTimeMillis() - startTs); - log.info(result); - } - } - } - - /** - * Construct client for accessing server using the existing channel. - */ - private BisqGrpcClient(ManagedChannel channel) { - this.channel = channel; - - getVersionStub = GetVersionGrpc.newBlockingStub(channel); - getBalanceStub = GetBalanceGrpc.newBlockingStub(channel); - getTradeStatisticsStub = GetTradeStatisticsGrpc.newBlockingStub(channel); - getOffersStub = GetOffersGrpc.newBlockingStub(channel); - getPaymentAccountsStub = GetPaymentAccountsGrpc.newBlockingStub(channel); - placeOfferBlockingStub = PlaceOfferGrpc.newBlockingStub(channel); - stopServerStub = StopServerGrpc.newBlockingStub(channel); - - CoreNetworkProtoResolver coreNetworkProtoResolver = new CoreNetworkProtoResolver(Clock.systemDefaultZone()); - //TODO - corePersistenceProtoResolver = new CorePersistenceProtoResolver(null, coreNetworkProtoResolver, null, null); - } - - private String getVersion() { - GetVersionRequest request = GetVersionRequest.newBuilder().build(); - try { - return getVersionStub.getVersion(request).getVersion(); - } catch (StatusRuntimeException e) { - return "RPC failed: " + e.getStatus(); - } - } - - private long getBalance() { - GetBalanceRequest request = GetBalanceRequest.newBuilder().build(); - try { - return getBalanceStub.getBalance(request).getBalance(); - } catch (StatusRuntimeException e) { - log.warn("RPC failed: {}", e.getStatus()); - return -1; - } - } - - private List getTradeStatistics() { - GetTradeStatisticsRequest request = GetTradeStatisticsRequest.newBuilder().build(); - try { - return getTradeStatisticsStub.getTradeStatistics(request).getTradeStatisticsList(); - } catch (StatusRuntimeException e) { - log.warn("RPC failed: {}", e.getStatus()); - return null; - } - } - - private List getOffers() { - GetOffersRequest request = GetOffersRequest.newBuilder().build(); - try { - return getOffersStub.getOffers(request).getOffersList(); - } catch (StatusRuntimeException e) { - log.warn("RPC failed: {}", e.getStatus()); - return null; - } - } - - private List getPaymentAccounts() { - GetPaymentAccountsRequest request = GetPaymentAccountsRequest.newBuilder().build(); - try { - return getPaymentAccountsStub.getPaymentAccounts(request).getPaymentAccountsList(); - } catch (StatusRuntimeException e) { - log.warn("RPC failed: {}", e.getStatus()); - return null; - } - } - - private boolean placeOffer(String currencyCode, - String directionAsString, - long priceAsLong, - boolean useMarketBasedPrice, - double marketPriceMargin, - long amountAsLong, - long minAmountAsLong, - double buyerSecurityDeposit, - String paymentAccountId) { - PlaceOfferRequest request = PlaceOfferRequest.newBuilder() - .setCurrencyCode(currencyCode) - .setDirection(directionAsString) - .setPrice(priceAsLong) - .setUseMarketBasedPrice(useMarketBasedPrice) - .setMarketPriceMargin(marketPriceMargin) - .setAmount(amountAsLong) - .setMinAmount(minAmountAsLong) - .setBuyerSecurityDeposit(buyerSecurityDeposit) - .setPaymentAccountId(paymentAccountId) - .build(); - try { - return placeOfferBlockingStub.placeOffer(request).getResult(); - } catch (StatusRuntimeException e) { - log.warn("RPC failed: {}", e.getStatus()); - return false; - } - } - - private void stopServer() { - StopServerRequest request = StopServerRequest.newBuilder().build(); - try { - stopServerStub.stopServer(request); - } catch (StatusRuntimeException e) { - log.warn("RPC failed: {}", e.getStatus()); - } - } - - private void shutdown() throws InterruptedException { - channel.shutdown().awaitTermination(1, TimeUnit.SECONDS); - System.exit(0); - } -} From eaad2e0a4c4bf943db1b14a3da6f71b494fa6d7b Mon Sep 17 00:00:00 2001 From: Chris Beams Date: Fri, 22 Nov 2019 12:54:34 +0100 Subject: [PATCH 08/14] Clean up protobuf/grpc config and dependencies This change: - Removes several superfluous dependencies not required for our purposes with gRPC - Cleans up the way Gradle source sets are managed for generated gRPC sources and classes - Makes use of Gradle's new `implementation`, `compileOnly` and `runtimeOnly` dependency configurations where changes were otherwise being made. See https://stackoverflow.com/a/47365147 for details. Remaining uses of the now-deprecated `compile` and `runtime` configurations should be eliminated in a refactoring separate and apart from the present gRPC API work. - Upgrades several existing dependencies to align with newer versions of the same dependencies introduced transitively by grpc-* 1.25.0 libraries, including: - protoc from 3.9.1 => 3.10.0 - gson from 2.7 => 2.8.5 Note that a number of the grpc-* libraries depend on Guava v28, and our existing dependency on Guava v20 has *not* been upgraded to this newer version because it is incompatible with the way we have used Guava's Futures API. It appears that the grpc-* libraries function correctly against this older version of Guava, and more investigation would be required see whether upgrading our uses to the new Guava API is feasible / worth it. The way we are preventing this upgrade is with the use of `exclude(module: "guava")` directives on grpc-* dependencies. --- build.gradle | 91 +++++++++++----------------- gradle/witness/gradle-witness.gradle | 36 ++--------- 2 files changed, 43 insertions(+), 84 deletions(-) diff --git a/build.gradle b/build.gradle index 740a746be2e..e47ff373cb6 100644 --- a/build.gradle +++ b/build.gradle @@ -31,7 +31,6 @@ configure(subprojects) { bitcoinjVersion = 'a88d36d' btcdCli4jVersion = '975ff5d4' codecVersion = '1.9' - commonProtosVersion = '1.17.0' easybindVersion = '1.0.3' easyVersion = '4.0.1' findbugsVersion = '3.0.2' @@ -60,9 +59,9 @@ configure(subprojects) { logbackVersion = '1.1.10' lombokVersion = '1.18.2' mockitoVersion = '3.0.0' - nettyTcNativeVersion = '2.0.27.Final' netlayerVersion = '0.6.5.2' - protobufVersion = '3.9.1' + protobufVersion = '3.10.0' + protocVersion = protobufVersion pushyVersion = '0.13.2' qrgenVersion = '1.3' sarxosVersion = '0.3.12' @@ -171,7 +170,7 @@ configure(project(':common')) { protobuf { protoc { - artifact = "com.google.protobuf:protoc:$protobufVersion" + artifact = "com.google.protobuf:protoc:$protocVersion" } } @@ -180,7 +179,7 @@ configure(project(':common')) { compile "org.openjfx:javafx-base:$javafxVersion:$os" compile "org.openjfx:javafx-graphics:$javafxVersion:$os" compile "com.google.protobuf:protobuf-java:$protobufVersion" - compile 'com.google.code.gson:gson:2.7' + compile 'com.google.code.gson:gson:2.8.5' compile "org.springframework:spring-core:$springVersion" compile "org.slf4j:slf4j-api:$slf4jVersion" compile "ch.qos.logback:logback-core:$logbackVersion" @@ -232,26 +231,6 @@ configure(project(':p2p')) { configure(project(':core')) { apply plugin: 'com.google.protobuf' - // FIXME we dont want to have one src dir inside the other.... - sourceSets.main.java.srcDir "$buildDir/generated/source/proto/main" - sourceSets.main.java.srcDir "$buildDir/generated/source/proto/main/java" - - protobuf { - protoc { - artifact = "com.google.protobuf:protoc:$protobufVersion" - } - plugins { - grpc { - artifact = "io.grpc:protoc-gen-grpc-java:$grpcVersion" - } - } - generateProtoTasks { - all()*.plugins { - grpc {} - } - } - } - dependencies { compile project(':assets') compile project(':p2p') @@ -277,44 +256,20 @@ configure(project(':core')) { compile("com.fasterxml.jackson.core:jackson-databind:$jacksonVersion") { exclude(module: 'jackson-annotations') } - - compileOnly "org.projectlombok:lombok:$lombokVersion" - annotationProcessor "org.projectlombok:lombok:$lombokVersion" - - compile "com.google.protobuf:protobuf-java:$protobufVersion" - compile "com.google.api.grpc:proto-google-common-protos:$commonProtosVersion" - - // FIXME Not clear which of the following libs have a newer version of guava which is not compatible with ours - compile ("io.grpc:grpc-alts:$grpcVersion") { + implementation "com.google.protobuf:protobuf-java:$protobufVersion" + implementation("io.grpc:grpc-protobuf:$grpcVersion") { exclude(module: 'guava') } - - compile ("io.grpc:grpc-netty:$grpcVersion") { + implementation("io.grpc:grpc-stub:$grpcVersion") { exclude(module: 'guava') } - - compile ("io.grpc:grpc-protobuf:$grpcVersion") { - exclude(module: 'guava') - } - - compile ("io.grpc:grpc-stub:$grpcVersion") { + compileOnly "javax.annotation:javax.annotation-api:1.2" + runtimeOnly ("io.grpc:grpc-netty-shaded:$grpcVersion") { exclude(module: 'guava') } - - // Used for TLS in HelloWorldServerTls - compile "io.netty:netty-tcnative-boringssl-static:${nettyTcNativeVersion}" - compileOnly "org.projectlombok:lombok:$lombokVersion" - compileOnly "javax.annotation:javax.annotation-api:1.2" annotationProcessor "org.projectlombok:lombok:$lombokVersion" - testCompile "io.grpc:grpc-testing:${grpcVersion}" - testCompile "org.mockito:mockito-core:$mockitoVersion" - testCompile "org.springframework:spring-test:$springVersion" - testCompile "com.natpryce:make-it-easy:$easyVersion" - testCompileOnly "org.projectlombok:lombok:$lombokVersion" - testAnnotationProcessor "org.projectlombok:lombok:$lombokVersion" - testCompile "org.mockito:mockito-core:$mockitoVersion" testCompile "org.springframework:spring-test:$springVersion" testCompile "com.natpryce:make-it-easy:$easyVersion" @@ -323,6 +278,25 @@ configure(project(':core')) { testAnnotationProcessor "org.projectlombok:lombok:$lombokVersion" } + protobuf { + protoc { + artifact = "com.google.protobuf:protoc:${protocVersion}" + } + plugins { + grpc { + artifact = "io.grpc:protoc-gen-grpc-java:${grpcVersion}" + } + } + generateProtoTasks { + all()*.plugins { grpc {} } + } + } + + sourceSets.main.java.srcDirs += [ + 'build/generated/source/proto/main/grpc', + 'build/generated/source/proto/main/java' + ] + test { systemProperty 'jdk.attach.allowAttachSelf', true } @@ -333,6 +307,12 @@ configure(project(':cli')) { dependencies { compile project(':core') + implementation("io.grpc:grpc-core:$grpcVersion") { + exclude(module: 'guava') + } + implementation("io.grpc:grpc-stub:$grpcVersion") { + exclude(module: 'guava') + } compileOnly "org.projectlombok:lombok:$lombokVersion" annotationProcessor "org.projectlombok:lombok:$lombokVersion" } @@ -479,6 +459,9 @@ configure(project(':grpc')) { dependencies { compile project(':core') + implementation("io.grpc:grpc-stub:$grpcVersion") { + exclude(module: 'guava') + } compileOnly "org.projectlombok:lombok:$lombokVersion" compileOnly "javax.annotation:javax.annotation-api:1.2" annotationProcessor "org.projectlombok:lombok:$lombokVersion" diff --git a/gradle/witness/gradle-witness.gradle b/gradle/witness/gradle-witness.gradle index 423c357f312..1a1f47ba50a 100644 --- a/gradle/witness/gradle-witness.gradle +++ b/gradle/witness/gradle-witness.gradle @@ -17,7 +17,7 @@ dependencyVerification { 'ch.qos.logback:logback-classic:e66efc674e94837344bc5b748ff510c37a44eeff86cbfdbf9e714ef2eb374013', 'ch.qos.logback:logback-core:4cd46fa17d77057b39160058df2f21ebbc2aded51d0edcc25d2c1cecc042a005', 'com.fasterxml.jackson.core:jackson-annotations:2566b3a6662afa3c6af4f5b25006cb46be2efc68f1b5116291d6998a8cdf7ed3', - 'com.fasterxml.jackson.core:jackson-core:3083079be6088db2ed0a0c6ff92204e0aa48fa1de9db5b59c468f35acf882c2c', + 'com.fasterxml.jackson.core:jackson-core:39a74610521d7fb9eb3f437bb8739bbf47f6435be12d17bf954c731a0c6352bb', 'com.fasterxml.jackson.core:jackson-databind:fcf3c2b0c332f5f54604f7e27fa7ee502378a2cc5df6a944bbfae391872c32ff', 'com.github.JesusMcCloud.netlayer:tor.external:10c3acfbcf8f80154a3f10640c4d4d275c4fc9baaf5c476d631da4e2382aaa5b', 'com.github.JesusMcCloud.netlayer:tor.native:fba4dca6a139af741c36713bcfe3680a92870009dbb59a3a14f9dae7f6cd116e', @@ -32,19 +32,12 @@ dependencyVerification { 'com.github.ravn:jsocks:3c71600af027b2b6d4244e4ad14d98ff2352a379410daebefff5d8cd48d742a4', 'com.github.sarxos:webcam-capture:d960b7ea8ec3ddf2df0725ef214c3fccc9699ea7772df37f544e1f8e4fd665f6', 'com.google.android:annotations:ba734e1e84c09d615af6a09d33034b4f0442f8772dec120efb376d86a565ae15', - 'com.google.api.grpc:proto-google-common-protos:ad25472c73ee470606fb500b376ae5a97973d5406c2f5c3b7d07fb25b4648b65', - 'com.google.auth:google-auth-library-credentials:aaeea9333fff9b763715bca0174ec76c4f9551b5731c89a95f263cdc82b4b56e', - 'com.google.auth:google-auth-library-oauth2-http:fa9a1589c8bc279416988d437c2636967cd5e4eff70fbddc986b9c5a77b0231b', - 'com.google.auto.value:auto-value-annotations:3bf4b9e74a6bf0f38ac70af571e0f8a9d85ccba4c0693a72fea9ea46def0d5a0', + 'com.google.api.grpc:proto-google-common-protos:bd60cd7a423b00fb824c27bdd0293aaf4781be1daba6ed256311103fb4b84108', 'com.google.code.findbugs:jsr305:766ad2a0783f2687962c8ad74ceecc38a28b9f72a2d085ee438b7813e928d0c7', 'com.google.code.gson:gson:233a0149fc365c9f6edbd683cfe266b19bdc773be98eabdaf6b3c924b48e7d81', 'com.google.errorprone:error_prone_annotations:ec59f1b702d9afc09e8c3929f5c42777dec623a6ea2731ac694332c7d7680f5a', 'com.google.guava:guava:36a666e3b71ae7f0f0dca23654b67e086e6c93d192f60ba5dfd5519db6c288c8', - 'com.google.http-client:google-http-client-jackson2:480b67711dd75054b45ec4f88056e53fda9773145117a1a852c803e2cb4b84e0', - 'com.google.http-client:google-http-client:2b4353d8ca918f92f3a5fcd6b6b2de09858eae683423225773f24c828cd06cc8', 'com.google.inject:guice:d258ff1bd9b8b527872f8402648226658ad3149f1f40e74b0566d69e7e042fbc', - 'com.google.j2objc:j2objc-annotations:21af30c92267bd6122c0e0b4d20cccb6641a37eaf956c6540ec471d584e64a7b', - 'com.google.protobuf:protobuf-java-util:619b0b0dc344cb141e493cbedc5687c8fb7c985e609a1b035e621bfab2f89021', 'com.google.protobuf:protobuf-java:161d7d61a8cb3970891c299578702fd079646e032329d6c2cabf998d191437c9', 'com.google.zxing:core:11aae8fd974ab25faa8208be50468eb12349cd239e93e7c797377fa13e381729', 'com.google.zxing:javase:0ec23e2ec12664ddd6347c8920ad647bb3b9da290f897a88516014b56cc77eb9', @@ -55,38 +48,22 @@ dependencyVerification { 'com.nativelibs4java:bridj:101bcd9b6637e6bc16e56deb3daefba62b1f5e8e9e37e1b3e56e3b5860d659cf', 'com.squareup.okhttp:okhttp:b4c943138fcef2bcc9d2006b2250c4aabbedeafc5947ed7c0af7fd103ceb2707', 'com.squareup.okio:okio:114bdc1f47338a68bcbc95abf2f5cdc72beeec91812f2fcd7b521c1937876266', - 'commons-codec:commons-codec:e599d5318e97aa48f42136a2927e6dfa4e8881dff0e6c8e3109ddbbff51d7b7d', + 'commons-codec:commons-codec:ad19d2601c3abf0b946b5c3a4113e226a8c1e3305e395b90013b78dd94a723ce', 'commons-io:commons-io:cc6a41dc3eaacc9e440a6bd0d2890b20d36b4ee408fe2d67122f328bb6e01581', 'commons-logging:commons-logging:daddea1ea0be0f56978ab3006b8ac92834afeefbd9b7e4e6316fca57df0fa636', 'de.jensd:fontawesomefx-commons:5539bb3335ecb822dbf928546f57766eeb9f1516cc1417a064b5709629612149', 'de.jensd:fontawesomefx-materialdesignfont:dbad8dfdd1c85e298d5bbae25b2399aec9e85064db57b2427d10f3815aa98752', 'de.jensd:fontawesomefx:73bacc991a0a6f5cf0f911767c8db161e0949dbca61e8371eb4342e3da96887b', 'io.github.microutils:kotlin-logging:4992504fd3c6ecdf9ed10874b9508e758bb908af9e9d7af19a61e9afb6b7e27a', - 'io.grpc:grpc-alts:177aa1e578c10e274f8feedd6f555c2e7741c195a84f533f9a51fb82dbe8a596', 'io.grpc:grpc-api:a269094009588213ab5386a6fb92426b8056a130b2653d3b4e59e971f2f1ef08', - 'io.grpc:grpc-auth:782ae07923d53b56f54326e7b32480b425eb3df71deb5a4a33bbfc6487e706a4', 'io.grpc:grpc-context:f4c8f878c320f6fb56c1c14692618f6df8253314b556176e32727afbc5921a73', 'io.grpc:grpc-core:d67fa113fd9cc45a02710f9c41dda9c15191448c14e9e96fcc21839a41345d4c', - 'io.grpc:grpc-grpclb:aaac0d6063204dfc52abc51af94f16b6cecfd582bb477ee1d232e42920bf49e3', 'io.grpc:grpc-netty-shaded:9edfd45da473d2efbb5683fc3eaf1857e82d2148033d82dd558a7ac38731ea33', - 'io.grpc:grpc-netty:167e834788f6d4f7bd129bfb244d4e09d061a0e7165288378386ae871e3cfe51', 'io.grpc:grpc-protobuf-lite:9ba9aaa3e6997a04c707793c25e3ec88c6bad86f8d6f6b8b7a1a0c33ea2429d8', 'io.grpc:grpc-protobuf:454dae7e246dac25526ed5b795d97a5dafedd3cc2042cfc810f02051d7d3e3cb', 'io.grpc:grpc-stub:1532e291c0e9fd8230a6416c8ebbd902d99c7e2760241ae638ea761aa3dd5f43', - 'io.netty:netty-buffer:7b0171a4e8bcd573e08d9f2bba053c67b557ab5012106a5982ccbae5743814c0', - 'io.netty:netty-codec-http2:8bac9625eb68635396eb0c13c9cc0b22bde7c83d0cd2dae3fe9b6f9cf929e372', - 'io.netty:netty-codec-http:eb349c0f1b249af7c7a8fbbd1c761d65d9bc230880cd8d37feab9e8278292625', - 'io.netty:netty-codec-socks:7f14b3a95ee9aa5a26f66af668690578a81a883683ac1c4ca9e9afdf4d4c7894', - 'io.netty:netty-codec:e96ced697fb7df589da7c20c995e01f75a9cb246be242bbc4cd3b4af424ff189', - 'io.netty:netty-common:3d0a918d78292eeca02a7bb2188daa4e5053b6e29b71e6308309033e121242b5', - 'io.netty:netty-handler-proxy:25f22da21c29ab0d3b6b889412351bcfc5f9ccd42e07d2d5513d5c4eb571f343', - 'io.netty:netty-handler:11eda86500c33b9d386719b5419f513fd9c097d13894f25dd0c75b610d636e03', - 'io.netty:netty-resolver:89768242b6b7cce9bd9f5945ad21d1b4bae515c6b1bf03a8af5d1899779cebc9', - 'io.netty:netty-tcnative-boringssl-static:0ea1a935a1023a88e99a4f9b1aba2e3ff2799d4d1994f4bff848f85b367d48ed', - 'io.netty:netty-transport:dfa817a156ea263aa9ad8364a2e226527665c9722aca40a7945f228c2c14f1da', 'io.opencensus:opencensus-api:8e2cb0f6391d8eb0a1bcd01e7748883f0033b1941754f4ed3f19d2c3e4276fc8', 'io.opencensus:opencensus-contrib-grpc-metrics:29fc79401082301542cab89d7054d2f0825f184492654c950020553ef4ff0ef8', - 'io.opencensus:opencensus-contrib-http-util:d62fd27175a842bde135f6f6b1d6f25d42e9bd59a87bc98709a4760fe399ee14', 'io.perfmark:perfmark-api:b734ba2149712409a44eabdb799f64768578fee0defe1418bb108fe32ea43e1a', 'javax.inject:javax.inject:91c77044a50c481636c32d916fd89c9118a72195390452c81065080f957de7ff', 'net.glxn:qrgen:c85d9d8512d91e8ad11fe56259a7825bd50ce0245447e236cf168d1b17591882', @@ -95,14 +72,13 @@ dependencyVerification { 'network.bisq.btcd-cli4j:btcd-cli4j-core:203156fc63dc1202774de9818e4f21149549f79b25d356b08bb0c784be40c0e8', 'network.bisq.btcd-cli4j:btcd-cli4j-daemon:0a2783a851add6e3d8ae899ade48c041b250bfac64b6a4c5f6380ebcdbbe6848', 'org.apache.commons:commons-compress:5f2df1e467825e4cac5996d44890c4201c000b43c0b23cffc0782d28a0beb9b0', - 'org.apache.commons:commons-lang3:8ac96fc686512d777fca85e144f196cd7cfe0c0aec23127229497d1a38ff651c', - 'org.apache.httpcomponents:httpclient:6c7e3bb423d8c5574f28157fe42b4c38d6a3477bfa2954cfe5f330b14ecad8a9', - 'org.apache.httpcomponents:httpcore:d799522d579aac06b170603f8f080f6e3248dadc01f9652cdd7ea7bc318c21ce', + 'org.apache.commons:commons-lang3:734c8356420cc8e30c795d64fd1fcd5d44ea9d90342a2cc3262c5158fbc6d98b', + 'org.apache.httpcomponents:httpclient:db3d1b6c2d6a5e5ad47577ad61854e2f0e0936199b8e05eb541ed52349263135', + 'org.apache.httpcomponents:httpcore:d7f853dee87680b07293d30855b39b9eb56c1297bd16ff1cd6f19ddb8fa745fb', 'org.bitcoinj:orchid:f836325cfa0466a011cb755c9b0fee6368487a2352eb45f4306ad9e4c18de080', 'org.bouncycastle:bcpg-jdk15on:de3355b821fc81dd32e1f3f560d5b3eca1c678fd2400011d0bfc69fb91bcde85', 'org.bouncycastle:bcprov-jdk15on:963e1ee14f808ffb99897d848ddcdb28fa91ddda867eb18d303e82728f878349', 'org.codehaus.mojo:animal-sniffer-annotations:92654f493ecfec52082e76354f0ebf87648dc3d5cec2e3c3cdb947c016747a53', - 'org.conscrypt:conscrypt-openjdk-uber:27f4314bf01e5af288ade537f06cb6eb7f0c760aed4a8d7cf441de71de0a7abb', 'org.fxmisc.easybind:easybind:666af296dda6de68751668a62661571b5238ac6f1c07c8a204fc6f902b222aaf', 'org.jetbrains.kotlin:kotlin-stdlib-common:6c91dea17d7dce5f0b550c3de3305767e5fb46247b6d1eb7eca0ca1fe18458de', 'org.jetbrains.kotlin:kotlin-stdlib-jdk7:25e2409aba0ec37d2fd7c77727d7835b511879de8d9bf4862af0b493aabbe39e', From aff760514b112115c8b81da768a126cab720dbbb Mon Sep 17 00:00:00 2001 From: Chris Beams Date: Thu, 21 Nov 2019 22:54:23 +0100 Subject: [PATCH 09/14] Sever dependency from :desktop => :grpc The :grpc module will soon be renamed to :daemon. These two modules represent two separate and equal modes of running bisq, either as a desktop GUI or as a daemon. They are both applications, and one should not depend on the other as it would be illogical and confusing to model things that way. The reason for the current dependency from :desktop to :grpc is because :grpc is the home of BisqGrpcServer. This change moves this class up to :core, in a new bisq.core.grpc package, such that both the :desktop and :daemon applications can pull it in cleanly. The CoreApi 'facade' that BisqGrpcServer uses to abstract away bisq internals has been moved from bisq.core to bisq.core.grpc as well and for the same reasons detailed in 8b30c22d6. This change also renames the Java package for generated grpc types from bisq.grpc.protobuf to bisq.core.grpc (the same new package that BisqGrpcServer and CoreApi now live in). Again, this is for reasons of cohesion: BisqGrpcServer is the only user of these grpc-generated types, and they should logically live in the same package (even if they physically live in separate source dirs at the build level). --- build.gradle | 1 - .../main/java/bisq/cli/app/BisqCliMain.java | 28 +++++++++---------- .../java/bisq/core}/grpc/BisqGrpcServer.java | 27 ++---------------- .../java/bisq/core/{ => grpc}/CoreApi.java | 2 +- core/src/main/proto/grpc.proto | 2 +- .../java/bisq/grpc/BisqGrpcServerMain.java | 3 +- 6 files changed, 21 insertions(+), 42 deletions(-) rename {grpc/src/main/java/bisq => core/src/main/java/bisq/core}/grpc/BisqGrpcServer.java (88%) rename core/src/main/java/bisq/core/{ => grpc}/CoreApi.java (99%) diff --git a/build.gradle b/build.gradle index e47ff373cb6..3fd5a2aef33 100644 --- a/build.gradle +++ b/build.gradle @@ -336,7 +336,6 @@ configure(project(':desktop')) { dependencies { compile project(':core') - compile project(':grpc') compile "net.glxn:qrgen:$qrgenVersion" compile "de.jensd:fontawesomefx:$fontawesomefxVersion" compile "de.jensd:fontawesomefx-commons:$fontawesomefxCommonsVersion" diff --git a/cli/src/main/java/bisq/cli/app/BisqCliMain.java b/cli/src/main/java/bisq/cli/app/BisqCliMain.java index dbc78c641d6..5988324c121 100644 --- a/cli/src/main/java/bisq/cli/app/BisqCliMain.java +++ b/cli/src/main/java/bisq/cli/app/BisqCliMain.java @@ -17,6 +17,20 @@ package bisq.cli.app; +import bisq.core.grpc.GetBalanceGrpc; +import bisq.core.grpc.GetBalanceRequest; +import bisq.core.grpc.GetOffersGrpc; +import bisq.core.grpc.GetOffersRequest; +import bisq.core.grpc.GetPaymentAccountsGrpc; +import bisq.core.grpc.GetPaymentAccountsRequest; +import bisq.core.grpc.GetTradeStatisticsGrpc; +import bisq.core.grpc.GetTradeStatisticsRequest; +import bisq.core.grpc.GetVersionGrpc; +import bisq.core.grpc.GetVersionRequest; +import bisq.core.grpc.PlaceOfferGrpc; +import bisq.core.grpc.PlaceOfferRequest; +import bisq.core.grpc.StopServerGrpc; +import bisq.core.grpc.StopServerRequest; import bisq.core.payment.PaymentAccount; import bisq.core.proto.network.CoreNetworkProtoResolver; import bisq.core.proto.persistable.CorePersistenceProtoResolver; @@ -39,20 +53,6 @@ -import bisq.grpc.protobuf.GetBalanceGrpc; -import bisq.grpc.protobuf.GetBalanceRequest; -import bisq.grpc.protobuf.GetOffersGrpc; -import bisq.grpc.protobuf.GetOffersRequest; -import bisq.grpc.protobuf.GetPaymentAccountsGrpc; -import bisq.grpc.protobuf.GetPaymentAccountsRequest; -import bisq.grpc.protobuf.GetTradeStatisticsGrpc; -import bisq.grpc.protobuf.GetTradeStatisticsRequest; -import bisq.grpc.protobuf.GetVersionGrpc; -import bisq.grpc.protobuf.GetVersionRequest; -import bisq.grpc.protobuf.PlaceOfferGrpc; -import bisq.grpc.protobuf.PlaceOfferRequest; -import bisq.grpc.protobuf.StopServerGrpc; -import bisq.grpc.protobuf.StopServerRequest; import io.grpc.ManagedChannel; import io.grpc.ManagedChannelBuilder; import io.grpc.StatusRuntimeException; diff --git a/grpc/src/main/java/bisq/grpc/BisqGrpcServer.java b/core/src/main/java/bisq/core/grpc/BisqGrpcServer.java similarity index 88% rename from grpc/src/main/java/bisq/grpc/BisqGrpcServer.java rename to core/src/main/java/bisq/core/grpc/BisqGrpcServer.java index 293fe91e47d..8c7dbd454f7 100644 --- a/grpc/src/main/java/bisq/grpc/BisqGrpcServer.java +++ b/core/src/main/java/bisq/core/grpc/BisqGrpcServer.java @@ -15,9 +15,8 @@ * along with Bisq. If not, see . */ -package bisq.grpc; +package bisq.core.grpc; -import bisq.core.CoreApi; import bisq.core.offer.Offer; import bisq.core.payment.PaymentAccount; import bisq.core.trade.handlers.TransactionResultHandler; @@ -32,31 +31,11 @@ -import bisq.grpc.protobuf.GetBalanceGrpc; -import bisq.grpc.protobuf.GetBalanceReply; -import bisq.grpc.protobuf.GetBalanceRequest; -import bisq.grpc.protobuf.GetOffersGrpc; -import bisq.grpc.protobuf.GetOffersReply; -import bisq.grpc.protobuf.GetOffersRequest; -import bisq.grpc.protobuf.GetPaymentAccountsGrpc; -import bisq.grpc.protobuf.GetPaymentAccountsReply; -import bisq.grpc.protobuf.GetPaymentAccountsRequest; -import bisq.grpc.protobuf.GetTradeStatisticsGrpc; -import bisq.grpc.protobuf.GetTradeStatisticsReply; -import bisq.grpc.protobuf.GetTradeStatisticsRequest; -import bisq.grpc.protobuf.GetVersionGrpc; -import bisq.grpc.protobuf.GetVersionReply; -import bisq.grpc.protobuf.GetVersionRequest; -import bisq.grpc.protobuf.PlaceOfferGrpc; -import bisq.grpc.protobuf.PlaceOfferReply; -import bisq.grpc.protobuf.PlaceOfferRequest; -import bisq.grpc.protobuf.StopServerGrpc; -import bisq.grpc.protobuf.StopServerReply; -import bisq.grpc.protobuf.StopServerRequest; import io.grpc.Server; import io.grpc.ServerBuilder; import io.grpc.stub.StreamObserver; + /** * gRPC server. Gets a instance of BisqFacade passed to access data from the running Bisq instance. */ @@ -199,7 +178,7 @@ public void stop() { * Await termination on the main thread since the grpc library uses daemon threads. * Only used for headless version */ - void blockUntilShutdown() throws InterruptedException { + public void blockUntilShutdown() throws InterruptedException { if (server != null) { server.awaitTermination(); } diff --git a/core/src/main/java/bisq/core/CoreApi.java b/core/src/main/java/bisq/core/grpc/CoreApi.java similarity index 99% rename from core/src/main/java/bisq/core/CoreApi.java rename to core/src/main/java/bisq/core/grpc/CoreApi.java index 09d67e495ed..2877849147f 100644 --- a/core/src/main/java/bisq/core/CoreApi.java +++ b/core/src/main/java/bisq/core/grpc/CoreApi.java @@ -15,7 +15,7 @@ * along with Bisq. If not, see . */ -package bisq.core; +package bisq.core.grpc; import bisq.core.btc.Balances; import bisq.core.monetary.Price; diff --git a/core/src/main/proto/grpc.proto b/core/src/main/proto/grpc.proto index 4ad24c24887..33957fb4124 100644 --- a/core/src/main/proto/grpc.proto +++ b/core/src/main/proto/grpc.proto @@ -21,7 +21,7 @@ package io.bisq.protobuffer; // FIXME: IntelliJ does not recognize the import but the compiler does import "pb.proto"; -option java_package = "bisq.grpc.protobuf"; +option java_package = "bisq.core.grpc"; option java_multiple_files = true; /////////////////////////////////////////////////////////////////////////////////////////// diff --git a/grpc/src/main/java/bisq/grpc/BisqGrpcServerMain.java b/grpc/src/main/java/bisq/grpc/BisqGrpcServerMain.java index 7776686a7bb..c510ba5664d 100644 --- a/grpc/src/main/java/bisq/grpc/BisqGrpcServerMain.java +++ b/grpc/src/main/java/bisq/grpc/BisqGrpcServerMain.java @@ -17,11 +17,12 @@ package bisq.grpc; -import bisq.core.CoreApi; import bisq.core.app.BisqExecutable; import bisq.core.app.BisqHeadlessAppMain; import bisq.core.app.BisqSetup; import bisq.core.app.CoreModule; +import bisq.core.grpc.BisqGrpcServer; +import bisq.core.grpc.CoreApi; import bisq.common.UserThread; import bisq.common.app.AppModule; From 900c13ef8f47f4a17087a2cac6cd1139fdd584bc Mon Sep 17 00:00:00 2001 From: Chris Beams Date: Fri, 22 Nov 2019 19:39:46 +0100 Subject: [PATCH 10/14] Rename submodule grpc => daemon - Rename package bisq.grpc => bisq.daemon.app - Rename BisqGrpcApp => BisqDaemon - Rename BisqGrpcServerMain => BisqDaemonMain The script `bisq-grpc` has been renamed to `bisq-daemon` accordingly (and will later be customized to `bisqd`). To see everything in action, issue the following commands: $ gradle build $ ./bisq-daemon --appName=Bisq-throwaway --daoActivated=false $ echo getVersion | ./bisq-cli # in a second terminal 1.2.3 --- build.gradle | 6 +++--- .../src/main/java/bisq/daemon/app/BisqDaemon.java | 7 ++----- .../main/java/bisq/daemon/app/BisqDaemonMain.java | 15 ++++++--------- .../src/main/java/resources/logback.xml | 0 settings.gradle | 2 +- 5 files changed, 12 insertions(+), 18 deletions(-) rename grpc/src/main/java/bisq/grpc/BisqGrpcApp.java => daemon/src/main/java/bisq/daemon/app/BisqDaemon.java (82%) rename grpc/src/main/java/bisq/grpc/BisqGrpcServerMain.java => daemon/src/main/java/bisq/daemon/app/BisqDaemonMain.java (89%) rename {grpc => daemon}/src/main/java/resources/logback.xml (100%) diff --git a/build.gradle b/build.gradle index 3fd5a2aef33..fc019df6424 100644 --- a/build.gradle +++ b/build.gradle @@ -89,8 +89,8 @@ configure(subprojects) { configure([project(':cli'), + project(':daemon'), project(':desktop'), - project(':grpc'), project(':monitor'), project(':relay'), project(':seednode'), @@ -453,8 +453,8 @@ configure(project(':statsnode')) { } } -configure(project(':grpc')) { - mainClassName = 'bisq.grpc.BisqGrpcServerMain' +configure(project(':daemon')) { + mainClassName = 'bisq.daemon.app.BisqDaemonMain' dependencies { compile project(':core') diff --git a/grpc/src/main/java/bisq/grpc/BisqGrpcApp.java b/daemon/src/main/java/bisq/daemon/app/BisqDaemon.java similarity index 82% rename from grpc/src/main/java/bisq/grpc/BisqGrpcApp.java rename to daemon/src/main/java/bisq/daemon/app/BisqDaemon.java index b95bd2b1926..f813f84d3ed 100644 --- a/grpc/src/main/java/bisq/grpc/BisqGrpcApp.java +++ b/daemon/src/main/java/bisq/daemon/app/BisqDaemon.java @@ -15,12 +15,9 @@ * along with Bisq. If not, see . */ -package bisq.grpc; +package bisq.daemon.app; import bisq.core.app.BisqHeadlessApp; -/** - * Headless Bisq application. Only used if gRPC API runs in headless mode. - */ -public class BisqGrpcApp extends BisqHeadlessApp { +public class BisqDaemon extends BisqHeadlessApp { } diff --git a/grpc/src/main/java/bisq/grpc/BisqGrpcServerMain.java b/daemon/src/main/java/bisq/daemon/app/BisqDaemonMain.java similarity index 89% rename from grpc/src/main/java/bisq/grpc/BisqGrpcServerMain.java rename to daemon/src/main/java/bisq/daemon/app/BisqDaemonMain.java index c510ba5664d..81f1143fa15 100644 --- a/grpc/src/main/java/bisq/grpc/BisqGrpcServerMain.java +++ b/daemon/src/main/java/bisq/daemon/app/BisqDaemonMain.java @@ -15,7 +15,7 @@ * along with Bisq. If not, see . */ -package bisq.grpc; +package bisq.daemon.app; import bisq.core.app.BisqExecutable; import bisq.core.app.BisqHeadlessAppMain; @@ -36,19 +36,16 @@ import lombok.extern.slf4j.Slf4j; @Slf4j -/** - * Main class to start gRPC server with a headless BisqGrpcApp instance. - */ -public class BisqGrpcServerMain extends BisqHeadlessAppMain implements BisqSetup.BisqSetupListener { +public class BisqDaemonMain extends BisqHeadlessAppMain implements BisqSetup.BisqSetupListener { private static BisqGrpcServer bisqGrpcServer; public static void main(String[] args) throws Exception { if (BisqExecutable.setupInitialOptionParser(args)) { // For some reason the JavaFX launch process results in us losing the thread context class loader: reset it. // In order to work around a bug in JavaFX 8u25 and below, you must include the following code as the first line of your realMain method: - Thread.currentThread().setContextClassLoader(BisqGrpcServerMain.class.getClassLoader()); + Thread.currentThread().setContextClassLoader(BisqDaemonMain.class.getClassLoader()); - new BisqGrpcServerMain().execute(args); + new BisqDaemonMain().execute(args); } } @@ -67,8 +64,8 @@ protected void configUserThread() { @Override protected void launchApplication() { - headlessApp = new BisqGrpcApp(); - CommonSetup.setup(BisqGrpcServerMain.this.headlessApp); + headlessApp = new BisqDaemon(); + CommonSetup.setup(BisqDaemonMain.this.headlessApp); UserThread.execute(this::onApplicationLaunched); } diff --git a/grpc/src/main/java/resources/logback.xml b/daemon/src/main/java/resources/logback.xml similarity index 100% rename from grpc/src/main/java/resources/logback.xml rename to daemon/src/main/java/resources/logback.xml diff --git a/settings.gradle b/settings.gradle index 14a57ab1464..b12eb486d4d 100644 --- a/settings.gradle +++ b/settings.gradle @@ -3,12 +3,12 @@ include 'common' include 'p2p' include 'core' include 'cli' +include 'daemon' include 'desktop' include 'monitor' include 'pricenode' include 'relay' include 'seednode' include 'statsnode' -include 'grpc' rootProject.name = 'bisq' From 9fceba63e2e65a88cd39b079c3da525f9db01129 Mon Sep 17 00:00:00 2001 From: Chris Beams Date: Tue, 26 Nov 2019 18:03:50 +0100 Subject: [PATCH 11/14] Remove duplicate attempt to start BisqGrpcServer Problem: a stack trace was being thrown during daemon startup from BisqDaemonMain.onSetupComplete when it attempted to start a second BisqGrpcServer and failed to bind to the already-bound port. The first BisqGrpcServer is started in BisqDaemonMain.onApplicationStarted much earlier in the startup process. Solution: remove the second attempt to start the server by removing BisqDaemonMain's implementation of onSetupComplete, and in turn remove the now-obsolete bisqGrpcServer field as well. This change also eliminates the BisqGrpcServer.blockUntilShutdown method, which in turn called the underlying grpc server's awaitTermination method. As the comment there explained, this was thought to be necessary because grpc "does not use daemon threads by default", but this is actually incorrect. According to the grpc Javadoc at [1], "Grpc uses non-daemon Threads by default and thus a Server will continue to run even after the main thread has terminated." [1]: https://git.io/JePjn --- .../main/java/bisq/core/grpc/BisqGrpcServer.java | 10 ---------- .../java/bisq/daemon/app/BisqDaemonMain.java | 16 +--------------- 2 files changed, 1 insertion(+), 25 deletions(-) diff --git a/core/src/main/java/bisq/core/grpc/BisqGrpcServer.java b/core/src/main/java/bisq/core/grpc/BisqGrpcServer.java index 8c7dbd454f7..d3c5556d1b0 100644 --- a/core/src/main/java/bisq/core/grpc/BisqGrpcServer.java +++ b/core/src/main/java/bisq/core/grpc/BisqGrpcServer.java @@ -174,16 +174,6 @@ public void stop() { } } - /** - * Await termination on the main thread since the grpc library uses daemon threads. - * Only used for headless version - */ - public void blockUntilShutdown() throws InterruptedException { - if (server != null) { - server.awaitTermination(); - } - } - /////////////////////////////////////////////////////////////////////////////////////////// // Private /////////////////////////////////////////////////////////////////////////////////////////// diff --git a/daemon/src/main/java/bisq/daemon/app/BisqDaemonMain.java b/daemon/src/main/java/bisq/daemon/app/BisqDaemonMain.java index 81f1143fa15..f25d1be3b14 100644 --- a/daemon/src/main/java/bisq/daemon/app/BisqDaemonMain.java +++ b/daemon/src/main/java/bisq/daemon/app/BisqDaemonMain.java @@ -37,7 +37,6 @@ @Slf4j public class BisqDaemonMain extends BisqHeadlessAppMain implements BisqSetup.BisqSetupListener { - private static BisqGrpcServer bisqGrpcServer; public static void main(String[] args) throws Exception { if (BisqExecutable.setupInitialOptionParser(args)) { @@ -76,19 +75,6 @@ protected void onApplicationLaunched() { headlessApp.setGracefulShutDownHandler(this); } - @Override - public void onSetupComplete() { - CoreApi coreApi = injector.getInstance(CoreApi.class); - bisqGrpcServer = new BisqGrpcServer(coreApi); - - // If we start headless we need to keep the main thread busy... - try { - bisqGrpcServer.blockUntilShutdown(); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - /////////////////////////////////////////////////////////////////////////////////////////// // We continue with a series of synchronous execution tasks @@ -120,6 +106,6 @@ protected void onApplicationStarted() { super.onApplicationStarted(); CoreApi coreApi = injector.getInstance(CoreApi.class); - bisqGrpcServer = new BisqGrpcServer(coreApi); + new BisqGrpcServer(coreApi); } } From 1e8633b03be9085b6bdd05886066aca9e632cade Mon Sep 17 00:00:00 2001 From: Chris Beams Date: Wed, 27 Nov 2019 12:22:44 +0100 Subject: [PATCH 12/14] Organize io.grpc imports correctly And remove entry for the no longer used io.bisq.generated package. --- .idea/codeStyles/Project.xml | 2 +- cli/src/main/java/bisq/cli/app/BisqCliMain.java | 10 ++++------ core/src/main/java/bisq/core/grpc/BisqGrpcServer.java | 10 ++++------ 3 files changed, 9 insertions(+), 13 deletions(-) diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml index d52f38b3e8f..65ad21a8f9d 100644 --- a/.idea/codeStyles/Project.xml +++ b/.idea/codeStyles/Project.xml @@ -33,7 +33,7 @@ - + diff --git a/cli/src/main/java/bisq/cli/app/BisqCliMain.java b/cli/src/main/java/bisq/cli/app/BisqCliMain.java index 5988324c121..f6b1eca12d3 100644 --- a/cli/src/main/java/bisq/cli/app/BisqCliMain.java +++ b/cli/src/main/java/bisq/cli/app/BisqCliMain.java @@ -35,6 +35,10 @@ import bisq.core.proto.network.CoreNetworkProtoResolver; import bisq.core.proto.persistable.CorePersistenceProtoResolver; +import io.grpc.ManagedChannel; +import io.grpc.ManagedChannelBuilder; +import io.grpc.StatusRuntimeException; + import org.bitcoinj.core.Coin; import java.time.Clock; @@ -51,12 +55,6 @@ import static com.google.common.base.Preconditions.checkArgument; import static java.lang.String.format; - - -import io.grpc.ManagedChannel; -import io.grpc.ManagedChannelBuilder; -import io.grpc.StatusRuntimeException; - /** * gRPC client. * diff --git a/core/src/main/java/bisq/core/grpc/BisqGrpcServer.java b/core/src/main/java/bisq/core/grpc/BisqGrpcServer.java index d3c5556d1b0..55db5011175 100644 --- a/core/src/main/java/bisq/core/grpc/BisqGrpcServer.java +++ b/core/src/main/java/bisq/core/grpc/BisqGrpcServer.java @@ -22,6 +22,10 @@ import bisq.core.trade.handlers.TransactionResultHandler; import bisq.core.trade.statistics.TradeStatistics2; +import io.grpc.Server; +import io.grpc.ServerBuilder; +import io.grpc.stub.StreamObserver; + import java.io.IOException; import java.util.List; @@ -30,12 +34,6 @@ import lombok.extern.slf4j.Slf4j; - -import io.grpc.Server; -import io.grpc.ServerBuilder; -import io.grpc.stub.StreamObserver; - - /** * gRPC server. Gets a instance of BisqFacade passed to access data from the running Bisq instance. */ From d77ff101fbccda8ea3262fe41e53ded49d6b1bd6 Mon Sep 17 00:00:00 2001 From: Chris Beams Date: Mon, 20 Jan 2020 12:58:13 +0100 Subject: [PATCH 13/14] Reflect higher security deposit in placeOffer RPC comment Per review comment at https://github.com/bisq-network/bisq/pull/3888#discussion_r368481607 --- cli/src/main/java/bisq/cli/app/BisqCliMain.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cli/src/main/java/bisq/cli/app/BisqCliMain.java b/cli/src/main/java/bisq/cli/app/BisqCliMain.java index f6b1eca12d3..754a47fac43 100644 --- a/cli/src/main/java/bisq/cli/app/BisqCliMain.java +++ b/cli/src/main/java/bisq/cli/app/BisqCliMain.java @@ -130,7 +130,7 @@ private BisqCliMain(String host, int port) { result = paymentAccounts.toString(); break; case "placeOffer": - // test input: placeOffer CNY BUY 750000000 true -0.2251 1000000 500000 0.12 5a972121-c30a-4b0e-b519-b17b63795d16 + // test input: placeOffer CNY BUY 750000000 true -0.2251 1000000 500000 0.15 5a972121-c30a-4b0e-b519-b17b63795d16 // payment accountId and currency need to be adopted // We expect 9 params From 2a66d11cd3cfc56a4ba33003dc2e25635d940e36 Mon Sep 17 00:00:00 2001 From: Chris Beams Date: Mon, 20 Jan 2020 15:33:56 +0100 Subject: [PATCH 14/14] Exclude unnecessary dependency on animal-sniffer-plugin Per review comment https://github.com/bisq-network/bisq/pull/3888#discussion_r368480788 --- build.gradle | 8 +++++--- gradle/witness/gradle-witness.gradle | 1 - 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/build.gradle b/build.gradle index fc019df6424..d361cd0da22 100644 --- a/build.gradle +++ b/build.gradle @@ -259,13 +259,16 @@ configure(project(':core')) { implementation "com.google.protobuf:protobuf-java:$protobufVersion" implementation("io.grpc:grpc-protobuf:$grpcVersion") { exclude(module: 'guava') + exclude(module: 'animal-sniffer-annotations') } implementation("io.grpc:grpc-stub:$grpcVersion") { exclude(module: 'guava') + exclude(module: 'animal-sniffer-annotations') } compileOnly "javax.annotation:javax.annotation-api:1.2" runtimeOnly ("io.grpc:grpc-netty-shaded:$grpcVersion") { exclude(module: 'guava') + exclude(module: 'animal-sniffer-annotations') } compileOnly "org.projectlombok:lombok:$lombokVersion" annotationProcessor "org.projectlombok:lombok:$lombokVersion" @@ -309,9 +312,11 @@ configure(project(':cli')) { compile project(':core') implementation("io.grpc:grpc-core:$grpcVersion") { exclude(module: 'guava') + exclude(module: 'animal-sniffer-annotations') } implementation("io.grpc:grpc-stub:$grpcVersion") { exclude(module: 'guava') + exclude(module: 'animal-sniffer-annotations') } compileOnly "org.projectlombok:lombok:$lombokVersion" annotationProcessor "org.projectlombok:lombok:$lombokVersion" @@ -458,9 +463,6 @@ configure(project(':daemon')) { dependencies { compile project(':core') - implementation("io.grpc:grpc-stub:$grpcVersion") { - exclude(module: 'guava') - } compileOnly "org.projectlombok:lombok:$lombokVersion" compileOnly "javax.annotation:javax.annotation-api:1.2" annotationProcessor "org.projectlombok:lombok:$lombokVersion" diff --git a/gradle/witness/gradle-witness.gradle b/gradle/witness/gradle-witness.gradle index 1a1f47ba50a..9be698d7e9e 100644 --- a/gradle/witness/gradle-witness.gradle +++ b/gradle/witness/gradle-witness.gradle @@ -78,7 +78,6 @@ dependencyVerification { 'org.bitcoinj:orchid:f836325cfa0466a011cb755c9b0fee6368487a2352eb45f4306ad9e4c18de080', 'org.bouncycastle:bcpg-jdk15on:de3355b821fc81dd32e1f3f560d5b3eca1c678fd2400011d0bfc69fb91bcde85', 'org.bouncycastle:bcprov-jdk15on:963e1ee14f808ffb99897d848ddcdb28fa91ddda867eb18d303e82728f878349', - 'org.codehaus.mojo:animal-sniffer-annotations:92654f493ecfec52082e76354f0ebf87648dc3d5cec2e3c3cdb947c016747a53', 'org.fxmisc.easybind:easybind:666af296dda6de68751668a62661571b5238ac6f1c07c8a204fc6f902b222aaf', 'org.jetbrains.kotlin:kotlin-stdlib-common:6c91dea17d7dce5f0b550c3de3305767e5fb46247b6d1eb7eca0ca1fe18458de', 'org.jetbrains.kotlin:kotlin-stdlib-jdk7:25e2409aba0ec37d2fd7c77727d7835b511879de8d9bf4862af0b493aabbe39e',