diff --git a/cli/src/main/java/bisq/cli/CliMain.java b/cli/src/main/java/bisq/cli/CliMain.java index e3a340c8dca..e16c6289d7c 100644 --- a/cli/src/main/java/bisq/cli/CliMain.java +++ b/cli/src/main/java/bisq/cli/CliMain.java @@ -17,18 +17,14 @@ package bisq.cli; -import bisq.proto.grpc.GetBalanceGrpc; import bisq.proto.grpc.GetBalanceRequest; import bisq.proto.grpc.GetVersionGrpc; import bisq.proto.grpc.GetVersionRequest; -import bisq.proto.grpc.LockWalletGrpc; import bisq.proto.grpc.LockWalletRequest; -import bisq.proto.grpc.RemoveWalletPasswordGrpc; import bisq.proto.grpc.RemoveWalletPasswordRequest; -import bisq.proto.grpc.SetWalletPasswordGrpc; import bisq.proto.grpc.SetWalletPasswordRequest; -import bisq.proto.grpc.UnlockWalletGrpc; import bisq.proto.grpc.UnlockWalletRequest; +import bisq.proto.grpc.WalletGrpc; import io.grpc.ManagedChannelBuilder; import io.grpc.StatusRuntimeException; @@ -139,26 +135,26 @@ public static void main(String[] args) { } })); + var versionService = GetVersionGrpc.newBlockingStub(channel).withCallCredentials(credentials); + var walletService = WalletGrpc.newBlockingStub(channel).withCallCredentials(credentials); + try { switch (method) { case getversion: { - var stub = GetVersionGrpc.newBlockingStub(channel).withCallCredentials(credentials); var request = GetVersionRequest.newBuilder().build(); - var version = stub.getVersion(request).getVersion(); + var version = versionService.getVersion(request).getVersion(); out.println(version); exit(EXIT_SUCCESS); } case getbalance: { - var stub = GetBalanceGrpc.newBlockingStub(channel).withCallCredentials(credentials); var request = GetBalanceRequest.newBuilder().build(); - var reply = stub.getBalance(request); + var reply = walletService.getBalance(request); out.println(formatBalance(reply.getBalance())); exit(EXIT_SUCCESS); } case lockwallet: { - var stub = LockWalletGrpc.newBlockingStub(channel).withCallCredentials(credentials); var request = LockWalletRequest.newBuilder().build(); - stub.lockWallet(request); + walletService.lockWallet(request); out.println("wallet locked"); exit(EXIT_SUCCESS); } @@ -178,11 +174,10 @@ public static void main(String[] args) { err.println(nonOptionArgs.get(2) + " is not a number"); exit(EXIT_FAILURE); } - var stub = UnlockWalletGrpc.newBlockingStub(channel).withCallCredentials(credentials); var request = UnlockWalletRequest.newBuilder() .setPassword(nonOptionArgs.get(1)) .setTimeout(timeout).build(); - stub.unlockWallet(request); + walletService.unlockWallet(request); out.println("wallet unlocked"); exit(EXIT_SUCCESS); } @@ -191,9 +186,8 @@ public static void main(String[] args) { err.println("Error: no \"password\" specified"); exit(EXIT_FAILURE); } - var stub = RemoveWalletPasswordGrpc.newBlockingStub(channel).withCallCredentials(credentials); var request = RemoveWalletPasswordRequest.newBuilder().setPassword(nonOptionArgs.get(1)).build(); - stub.removeWalletPassword(request); + walletService.removeWalletPassword(request); out.println("wallet decrypted"); exit(EXIT_SUCCESS); } @@ -202,11 +196,10 @@ public static void main(String[] args) { err.println("Error: no \"password\" specified"); exit(EXIT_FAILURE); } - var stub = SetWalletPasswordGrpc.newBlockingStub(channel).withCallCredentials(credentials); var request = (nonOptionArgs.size() == 3) ? SetWalletPasswordRequest.newBuilder().setPassword(nonOptionArgs.get(1)).setNewPassword(nonOptionArgs.get(2)).build() : SetWalletPasswordRequest.newBuilder().setPassword(nonOptionArgs.get(1)).build(); - stub.setWalletPassword(request); + walletService.setWalletPassword(request); out.println("wallet encrypted" + (nonOptionArgs.size() == 2 ? "" : " with new password")); exit(EXIT_SUCCESS); } diff --git a/core/src/main/java/bisq/core/grpc/CoreApi.java b/core/src/main/java/bisq/core/grpc/CoreApi.java index ddb165b5788..a0671f4d3b0 100644 --- a/core/src/main/java/bisq/core/grpc/CoreApi.java +++ b/core/src/main/java/bisq/core/grpc/CoreApi.java @@ -17,8 +17,6 @@ package bisq.core.grpc; -import bisq.core.btc.Balances; -import bisq.core.btc.wallet.WalletsManager; import bisq.core.monetary.Price; import bisq.core.offer.CreateOfferService; import bisq.core.offer.Offer; @@ -32,59 +30,39 @@ import bisq.core.user.User; import bisq.common.app.Version; -import bisq.common.util.Tuple2; import org.bitcoinj.core.Coin; -import org.bitcoinj.crypto.KeyCrypterScrypt; import javax.inject.Inject; -import org.spongycastle.crypto.params.KeyParameter; - import java.util.ArrayList; import java.util.List; import java.util.Set; -import java.util.Timer; -import java.util.TimerTask; import lombok.extern.slf4j.Slf4j; -import javax.annotation.Nullable; - -import static bisq.core.grpc.ApiStatus.*; -import static java.util.concurrent.TimeUnit.SECONDS; - /** * 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 OfferBookService offerBookService; private final TradeStatisticsManager tradeStatisticsManager; private final CreateOfferService createOfferService; private final OpenOfferManager openOfferManager; - private final WalletsManager walletsManager; private final User user; - @Nullable - private String tempLockWalletPassword; - @Inject - public CoreApi(Balances balances, - OfferBookService offerBookService, + public CoreApi(OfferBookService offerBookService, TradeStatisticsManager tradeStatisticsManager, CreateOfferService createOfferService, OpenOfferManager openOfferManager, - WalletsManager walletsManager, User user) { - this.balances = balances; this.offerBookService = offerBookService; this.tradeStatisticsManager = tradeStatisticsManager; this.createOfferService = createOfferService; this.openOfferManager = openOfferManager; - this.walletsManager = walletsManager; this.user = user; } @@ -92,24 +70,6 @@ public String getVersion() { return Version.VERSION; } - public Tuple2 getAvailableBalance() { - if (!walletsManager.areWalletsAvailable()) - return new Tuple2<>(-1L, WALLET_NOT_AVAILABLE); - - if (walletsManager.areWalletsEncrypted()) - return new Tuple2<>(-1L, WALLET_IS_ENCRYPTED_WITH_UNLOCK_INSTRUCTION); - - try { - long balance = balances.getAvailableBalance().get().getValue(); - return new Tuple2<>(balance, OK); - } catch (Throwable t) { - // TODO Derive new ApiStatus codes from server stack traces. - t.printStackTrace(); - // TODO Fix bug causing NPE thrown by getAvailableBalance(). - return new Tuple2<>(-1L, INTERNAL); - } - } - public List getTradeStatistics() { return new ArrayList<>(tradeStatisticsManager.getObservableTradeStatisticsSet()); } @@ -185,96 +145,4 @@ public void placeOffer(String offerId, log::error); } - // Provided for automated wallet protection method testing, despite the - // security risks exposed by providing users the ability to decrypt their wallets. - public Tuple2 removeWalletPassword(String password) { - if (!walletsManager.areWalletsAvailable()) - return new Tuple2<>(false, WALLET_NOT_AVAILABLE); - - if (!walletsManager.areWalletsEncrypted()) - return new Tuple2<>(false, WALLET_NOT_ENCRYPTED); - - KeyCrypterScrypt keyCrypterScrypt = walletsManager.getKeyCrypterScrypt(); - if (keyCrypterScrypt == null) - return new Tuple2<>(false, WALLET_ENCRYPTER_NOT_AVAILABLE); - - KeyParameter aesKey = keyCrypterScrypt.deriveKey(password); - if (!walletsManager.checkAESKey(aesKey)) - return new Tuple2<>(false, INCORRECT_WALLET_PASSWORD); - - walletsManager.decryptWallets(aesKey); - return new Tuple2<>(true, OK); - } - - public Tuple2 setWalletPassword(String password, String newPassword) { - try { - if (!walletsManager.areWalletsAvailable()) - return new Tuple2<>(false, WALLET_NOT_AVAILABLE); - - KeyCrypterScrypt keyCrypterScrypt = walletsManager.getKeyCrypterScrypt(); - if (keyCrypterScrypt == null) - return new Tuple2<>(false, WALLET_ENCRYPTER_NOT_AVAILABLE); - - if (newPassword != null && !newPassword.isEmpty()) { - // TODO Validate new password before replacing old password. - if (!walletsManager.areWalletsEncrypted()) - return new Tuple2<>(false, WALLET_NOT_ENCRYPTED); - - KeyParameter aesKey = keyCrypterScrypt.deriveKey(password); - if (!walletsManager.checkAESKey(aesKey)) - return new Tuple2<>(false, INCORRECT_OLD_WALLET_PASSWORD); - - walletsManager.decryptWallets(aesKey); - aesKey = keyCrypterScrypt.deriveKey(newPassword); - walletsManager.encryptWallets(keyCrypterScrypt, aesKey); - return new Tuple2<>(true, OK); - } - - if (walletsManager.areWalletsEncrypted()) - return new Tuple2<>(false, WALLET_IS_ENCRYPTED); - - // TODO Validate new password. - KeyParameter aesKey = keyCrypterScrypt.deriveKey(password); - walletsManager.encryptWallets(keyCrypterScrypt, aesKey); - return new Tuple2<>(true, OK); - } catch (Throwable t) { - // TODO Derive new ApiStatus codes from server stack traces. - t.printStackTrace(); - return new Tuple2<>(false, INTERNAL); - } - } - - public Tuple2 lockWallet() { - if (tempLockWalletPassword != null) { - Tuple2 encrypted = setWalletPassword(tempLockWalletPassword, null); - tempLockWalletPassword = null; - if (!encrypted.second.equals(OK)) - return encrypted; - - return new Tuple2<>(true, OK); - } - return new Tuple2<>(false, WALLET_ALREADY_LOCKED); - } - - public Tuple2 unlockWallet(String password, long timeout) { - Tuple2 decrypted = removeWalletPassword(password); - if (!decrypted.second.equals(OK)) - return decrypted; - - TimerTask timerTask = new TimerTask() { - @Override - public void run() { - log.info("Locking wallet"); - setWalletPassword(password, null); - tempLockWalletPassword = null; - } - }; - Timer timer = new Timer("Lock Wallet Timer"); - timer.schedule(timerTask, SECONDS.toMillis(timeout)); - - // Cache wallet password for timeout (secs), in case - // user wants to lock the wallet for timeout expires. - tempLockWalletPassword = password; - return new Tuple2<>(true, OK); - } } diff --git a/core/src/main/java/bisq/core/grpc/CoreWalletService.java b/core/src/main/java/bisq/core/grpc/CoreWalletService.java new file mode 100644 index 00000000000..ec8c5b709a6 --- /dev/null +++ b/core/src/main/java/bisq/core/grpc/CoreWalletService.java @@ -0,0 +1,149 @@ +package bisq.core.grpc; + +import bisq.core.btc.Balances; +import bisq.core.btc.wallet.WalletsManager; + +import bisq.common.util.Tuple2; + +import org.bitcoinj.crypto.KeyCrypterScrypt; + +import javax.inject.Inject; + +import org.spongycastle.crypto.params.KeyParameter; + +import java.util.Timer; +import java.util.TimerTask; + +import lombok.extern.slf4j.Slf4j; + +import javax.annotation.Nullable; + +import static bisq.core.grpc.ApiStatus.*; +import static java.util.concurrent.TimeUnit.SECONDS; + +@Slf4j +class CoreWalletService { + + private final Balances balances; + private final WalletsManager walletsManager; + + @Nullable + private String tempLockWalletPassword; + + @Inject + public CoreWalletService(Balances balances, WalletsManager walletsManager) { + this.balances = balances; + this.walletsManager = walletsManager; + } + + public Tuple2 getAvailableBalance() { + if (!walletsManager.areWalletsAvailable()) + return new Tuple2<>(-1L, WALLET_NOT_AVAILABLE); + + if (walletsManager.areWalletsEncrypted()) + return new Tuple2<>(-1L, WALLET_IS_ENCRYPTED_WITH_UNLOCK_INSTRUCTION); + + try { + long balance = balances.getAvailableBalance().get().getValue(); + return new Tuple2<>(balance, OK); + } catch (Throwable t) { + // TODO Derive new ApiStatus codes from server stack traces. + t.printStackTrace(); + // TODO Fix bug causing NPE thrown by getAvailableBalance(). + return new Tuple2<>(-1L, INTERNAL); + } + } + + public Tuple2 setWalletPassword(String password, String newPassword) { + try { + if (!walletsManager.areWalletsAvailable()) + return new Tuple2<>(false, WALLET_NOT_AVAILABLE); + + KeyCrypterScrypt keyCrypterScrypt = walletsManager.getKeyCrypterScrypt(); + if (keyCrypterScrypt == null) + return new Tuple2<>(false, WALLET_ENCRYPTER_NOT_AVAILABLE); + + if (newPassword != null && !newPassword.isEmpty()) { + // TODO Validate new password before replacing old password. + if (!walletsManager.areWalletsEncrypted()) + return new Tuple2<>(false, WALLET_NOT_ENCRYPTED); + + KeyParameter aesKey = keyCrypterScrypt.deriveKey(password); + if (!walletsManager.checkAESKey(aesKey)) + return new Tuple2<>(false, INCORRECT_OLD_WALLET_PASSWORD); + + walletsManager.decryptWallets(aesKey); + aesKey = keyCrypterScrypt.deriveKey(newPassword); + walletsManager.encryptWallets(keyCrypterScrypt, aesKey); + return new Tuple2<>(true, OK); + } + + if (walletsManager.areWalletsEncrypted()) + return new Tuple2<>(false, WALLET_IS_ENCRYPTED); + + // TODO Validate new password. + KeyParameter aesKey = keyCrypterScrypt.deriveKey(password); + walletsManager.encryptWallets(keyCrypterScrypt, aesKey); + return new Tuple2<>(true, OK); + } catch (Throwable t) { + // TODO Derive new ApiStatus codes from server stack traces. + t.printStackTrace(); + return new Tuple2<>(false, INTERNAL); + } + } + + public Tuple2 lockWallet() { + if (tempLockWalletPassword != null) { + Tuple2 encrypted = setWalletPassword(tempLockWalletPassword, null); + tempLockWalletPassword = null; + if (!encrypted.second.equals(OK)) + return encrypted; + + return new Tuple2<>(true, OK); + } + return new Tuple2<>(false, WALLET_ALREADY_LOCKED); + } + + public Tuple2 unlockWallet(String password, long timeout) { + Tuple2 decrypted = removeWalletPassword(password); + if (!decrypted.second.equals(OK)) + return decrypted; + + TimerTask timerTask = new TimerTask() { + @Override + public void run() { + log.info("Locking wallet"); + setWalletPassword(password, null); + tempLockWalletPassword = null; + } + }; + Timer timer = new Timer("Lock Wallet Timer"); + timer.schedule(timerTask, SECONDS.toMillis(timeout)); + + // Cache wallet password for timeout (secs), in case + // user wants to lock the wallet for timeout expires. + tempLockWalletPassword = password; + return new Tuple2<>(true, OK); + } + + // Provided for automated wallet protection method testing, despite the + // security risks exposed by providing users the ability to decrypt their wallets. + public Tuple2 removeWalletPassword(String password) { + if (!walletsManager.areWalletsAvailable()) + return new Tuple2<>(false, WALLET_NOT_AVAILABLE); + + if (!walletsManager.areWalletsEncrypted()) + return new Tuple2<>(false, WALLET_NOT_ENCRYPTED); + + KeyCrypterScrypt keyCrypterScrypt = walletsManager.getKeyCrypterScrypt(); + if (keyCrypterScrypt == null) + return new Tuple2<>(false, WALLET_ENCRYPTER_NOT_AVAILABLE); + + KeyParameter aesKey = keyCrypterScrypt.deriveKey(password); + if (!walletsManager.checkAESKey(aesKey)) + return new Tuple2<>(false, INCORRECT_WALLET_PASSWORD); + + walletsManager.decryptWallets(aesKey); + return new Tuple2<>(true, OK); + } +} diff --git a/core/src/main/java/bisq/core/grpc/GrpcServer.java b/core/src/main/java/bisq/core/grpc/GrpcServer.java index 0a379e0b3aa..2b3543572b1 100644 --- a/core/src/main/java/bisq/core/grpc/GrpcServer.java +++ b/core/src/main/java/bisq/core/grpc/GrpcServer.java @@ -24,9 +24,6 @@ import bisq.common.config.Config; -import bisq.proto.grpc.GetBalanceGrpc; -import bisq.proto.grpc.GetBalanceReply; -import bisq.proto.grpc.GetBalanceRequest; import bisq.proto.grpc.GetOffersGrpc; import bisq.proto.grpc.GetOffersReply; import bisq.proto.grpc.GetOffersRequest; @@ -39,27 +36,18 @@ import bisq.proto.grpc.GetVersionGrpc; import bisq.proto.grpc.GetVersionReply; import bisq.proto.grpc.GetVersionRequest; -import bisq.proto.grpc.LockWalletGrpc; -import bisq.proto.grpc.LockWalletReply; -import bisq.proto.grpc.LockWalletRequest; import bisq.proto.grpc.PlaceOfferGrpc; import bisq.proto.grpc.PlaceOfferReply; import bisq.proto.grpc.PlaceOfferRequest; -import bisq.proto.grpc.RemoveWalletPasswordGrpc; -import bisq.proto.grpc.RemoveWalletPasswordReply; -import bisq.proto.grpc.RemoveWalletPasswordRequest; -import bisq.proto.grpc.SetWalletPasswordGrpc; -import bisq.proto.grpc.SetWalletPasswordReply; -import bisq.proto.grpc.SetWalletPasswordRequest; -import bisq.proto.grpc.UnlockWalletGrpc; -import bisq.proto.grpc.UnlockWalletReply; -import bisq.proto.grpc.UnlockWalletRequest; +import io.grpc.Server; import io.grpc.ServerBuilder; -import io.grpc.StatusRuntimeException; import io.grpc.stub.StreamObserver; +import javax.inject.Inject; + import java.io.IOException; +import java.io.UncheckedIOException; import java.util.stream.Collectors; @@ -69,36 +57,32 @@ public class GrpcServer { private final CoreApi coreApi; - private final int port; + private final Server server; - public GrpcServer(Config config, CoreApi coreApi) { + @Inject + public GrpcServer(Config config, CoreApi coreApi, GrpcWalletService walletService) { this.coreApi = coreApi; - this.port = config.apiPort; + this.server = ServerBuilder.forPort(config.apiPort) + .addService(new GetVersionService()) + .addService(new GetTradeStatisticsService()) + .addService(new GetOffersService()) + .addService(new GetPaymentAccountsService()) + .addService(new PlaceOfferService()) + .addService(walletService) + .intercept(new PasswordAuthInterceptor(config.apiPassword)) + .build(); + } + public void start() { try { - var server = ServerBuilder.forPort(port) - .addService(new GetVersionService()) - .addService(new GetBalanceService()) - .addService(new GetTradeStatisticsService()) - .addService(new GetOffersService()) - .addService(new GetPaymentAccountsService()) - .addService(new LockWalletService()) - .addService(new PlaceOfferService()) - .addService(new RemoveWalletPasswordService()) - .addService(new SetWalletPasswordService()) - .addService(new UnlockWalletService()) - .intercept(new PasswordAuthInterceptor(config.apiPassword)) - .build() - .start(); - - log.info("listening on port {}", port); + server.start(); + log.info("listening on port {}", server.getPort()); Runtime.getRuntime().addShutdownHook(new Thread(() -> { server.shutdown(); log.info("shutdown complete"); })); - - } catch (IOException e) { - log.error(e.toString(), e); + } catch (IOException ex) { + throw new UncheckedIOException(ex); } } @@ -111,21 +95,6 @@ public void getVersion(GetVersionRequest req, StreamObserver re } } - class GetBalanceService extends GetBalanceGrpc.GetBalanceImplBase { - @Override - public void getBalance(GetBalanceRequest req, StreamObserver responseObserver) { - var result = coreApi.getAvailableBalance(); - if (!result.second.equals(ApiStatus.OK)) { - StatusRuntimeException ex = new StatusRuntimeException(result.second.getGrpcStatus() - .withDescription(result.second.getDescription())); - responseObserver.onError(ex); - throw ex; - } - var reply = GetBalanceReply.newBuilder().setBalance(result.first).build(); - responseObserver.onNext(reply); - responseObserver.onCompleted(); - } - } class GetTradeStatisticsService extends GetTradeStatisticsGrpc.GetTradeStatisticsImplBase { @Override @@ -192,72 +161,4 @@ public void placeOffer(PlaceOfferRequest req, StreamObserver re resultHandler); } } - - class RemoveWalletPasswordService extends RemoveWalletPasswordGrpc.RemoveWalletPasswordImplBase { - @Override - public void removeWalletPassword(RemoveWalletPasswordRequest req, - StreamObserver responseObserver) { - var result = coreApi.removeWalletPassword(req.getPassword()); - if (!result.second.equals(ApiStatus.OK)) { - StatusRuntimeException ex = new StatusRuntimeException(result.second.getGrpcStatus() - .withDescription(result.second.getDescription())); - responseObserver.onError(ex); - throw ex; - } - var reply = RemoveWalletPasswordReply.newBuilder().build(); - responseObserver.onNext(reply); - responseObserver.onCompleted(); - } - } - - class SetWalletPasswordService extends SetWalletPasswordGrpc.SetWalletPasswordImplBase { - @Override - public void setWalletPassword(SetWalletPasswordRequest req, - StreamObserver responseObserver) { - var result = coreApi.setWalletPassword(req.getPassword(), req.getNewPassword()); - if (!result.second.equals(ApiStatus.OK)) { - StatusRuntimeException ex = new StatusRuntimeException(result.second.getGrpcStatus() - .withDescription(result.second.getDescription())); - responseObserver.onError(ex); - throw ex; - } - var reply = SetWalletPasswordReply.newBuilder().build(); - responseObserver.onNext(reply); - responseObserver.onCompleted(); - } - } - - class LockWalletService extends LockWalletGrpc.LockWalletImplBase { - @Override - public void lockWallet(LockWalletRequest req, - StreamObserver responseObserver) { - var result = coreApi.lockWallet(); - if (!result.second.equals(ApiStatus.OK)) { - StatusRuntimeException ex = new StatusRuntimeException(result.second.getGrpcStatus() - .withDescription(result.second.getDescription())); - responseObserver.onError(ex); - throw ex; - } - var reply = LockWalletReply.newBuilder().build(); - responseObserver.onNext(reply); - responseObserver.onCompleted(); - } - } - - class UnlockWalletService extends UnlockWalletGrpc.UnlockWalletImplBase { - @Override - public void unlockWallet(UnlockWalletRequest req, - StreamObserver responseObserver) { - var result = coreApi.unlockWallet(req.getPassword(), req.getTimeout()); - if (!result.second.equals(ApiStatus.OK)) { - StatusRuntimeException ex = new StatusRuntimeException(result.second.getGrpcStatus() - .withDescription(result.second.getDescription())); - responseObserver.onError(ex); - throw ex; - } - var reply = UnlockWalletReply.newBuilder().build(); - responseObserver.onNext(reply); - responseObserver.onCompleted(); - } - } } diff --git a/core/src/main/java/bisq/core/grpc/GrpcWalletService.java b/core/src/main/java/bisq/core/grpc/GrpcWalletService.java new file mode 100644 index 00000000000..0d5ea8fd79a --- /dev/null +++ b/core/src/main/java/bisq/core/grpc/GrpcWalletService.java @@ -0,0 +1,102 @@ +package bisq.core.grpc; + +import bisq.proto.grpc.GetBalanceReply; +import bisq.proto.grpc.GetBalanceRequest; +import bisq.proto.grpc.LockWalletReply; +import bisq.proto.grpc.LockWalletRequest; +import bisq.proto.grpc.RemoveWalletPasswordReply; +import bisq.proto.grpc.RemoveWalletPasswordRequest; +import bisq.proto.grpc.SetWalletPasswordReply; +import bisq.proto.grpc.SetWalletPasswordRequest; +import bisq.proto.grpc.UnlockWalletReply; +import bisq.proto.grpc.UnlockWalletRequest; +import bisq.proto.grpc.WalletGrpc; + +import io.grpc.StatusRuntimeException; +import io.grpc.stub.StreamObserver; + +import javax.inject.Inject; + +class GrpcWalletService extends WalletGrpc.WalletImplBase { + + private final CoreWalletService walletService; + + @Inject + public GrpcWalletService(CoreWalletService walletService) { + this.walletService = walletService; + } + + @Override + public void getBalance(GetBalanceRequest req, StreamObserver responseObserver) { + var result = walletService.getAvailableBalance(); + if (!result.second.equals(ApiStatus.OK)) { + StatusRuntimeException ex = new StatusRuntimeException(result.second.getGrpcStatus() + .withDescription(result.second.getDescription())); + responseObserver.onError(ex); + throw ex; + } + var reply = GetBalanceReply.newBuilder().setBalance(result.first).build(); + responseObserver.onNext(reply); + responseObserver.onCompleted(); + } + + @Override + public void setWalletPassword(SetWalletPasswordRequest req, + StreamObserver responseObserver) { + var result = walletService.setWalletPassword(req.getPassword(), req.getNewPassword()); + if (!result.second.equals(ApiStatus.OK)) { + StatusRuntimeException ex = new StatusRuntimeException(result.second.getGrpcStatus() + .withDescription(result.second.getDescription())); + responseObserver.onError(ex); + throw ex; + } + var reply = SetWalletPasswordReply.newBuilder().build(); + responseObserver.onNext(reply); + responseObserver.onCompleted(); + } + + @Override + public void removeWalletPassword(RemoveWalletPasswordRequest req, + StreamObserver responseObserver) { + var result = walletService.removeWalletPassword(req.getPassword()); + if (!result.second.equals(ApiStatus.OK)) { + StatusRuntimeException ex = new StatusRuntimeException(result.second.getGrpcStatus() + .withDescription(result.second.getDescription())); + responseObserver.onError(ex); + throw ex; + } + var reply = RemoveWalletPasswordReply.newBuilder().build(); + responseObserver.onNext(reply); + responseObserver.onCompleted(); + } + + @Override + public void lockWallet(LockWalletRequest req, + StreamObserver responseObserver) { + var result = walletService.lockWallet(); + if (!result.second.equals(ApiStatus.OK)) { + StatusRuntimeException ex = new StatusRuntimeException(result.second.getGrpcStatus() + .withDescription(result.second.getDescription())); + responseObserver.onError(ex); + throw ex; + } + var reply = LockWalletReply.newBuilder().build(); + responseObserver.onNext(reply); + responseObserver.onCompleted(); + } + + @Override + public void unlockWallet(UnlockWalletRequest req, + StreamObserver responseObserver) { + var result = walletService.unlockWallet(req.getPassword(), req.getTimeout()); + if (!result.second.equals(ApiStatus.OK)) { + StatusRuntimeException ex = new StatusRuntimeException(result.second.getGrpcStatus() + .withDescription(result.second.getDescription())); + responseObserver.onError(ex); + throw ex; + } + var reply = UnlockWalletReply.newBuilder().build(); + responseObserver.onNext(reply); + responseObserver.onCompleted(); + } +} diff --git a/daemon/src/main/java/bisq/daemon/app/BisqDaemonMain.java b/daemon/src/main/java/bisq/daemon/app/BisqDaemonMain.java index 698f8ebe92d..36dbd4a351b 100644 --- a/daemon/src/main/java/bisq/daemon/app/BisqDaemonMain.java +++ b/daemon/src/main/java/bisq/daemon/app/BisqDaemonMain.java @@ -98,7 +98,7 @@ protected void startApplication() { protected void onApplicationStarted() { super.onApplicationStarted(); - CoreApi coreApi = injector.getInstance(CoreApi.class); - new GrpcServer(config, coreApi); + GrpcServer grpcServer = injector.getInstance(GrpcServer.class); + grpcServer.start(); } } diff --git a/proto/src/main/proto/grpc.proto b/proto/src/main/proto/grpc.proto index d7dbf1df327..b8db4c6d24b 100644 --- a/proto/src/main/proto/grpc.proto +++ b/proto/src/main/proto/grpc.proto @@ -39,22 +39,6 @@ message GetVersionReply { string version = 1; } -/////////////////////////////////////////////////////////////////////////////////////////// -// Balance -/////////////////////////////////////////////////////////////////////////////////////////// - -service GetBalance { - rpc GetBalance (GetBalanceRequest) returns (GetBalanceReply) { - } -} - -message GetBalanceRequest { -} - -message GetBalanceReply { - uint64 balance = 1; -} - /////////////////////////////////////////////////////////////////////////////////////////// // TradeStatistics /////////////////////////////////////////////////////////////////////////////////////////// @@ -129,28 +113,27 @@ message PlaceOfferReply { } /////////////////////////////////////////////////////////////////////////////////////////// -// RemoveWalletPassword +// Wallet /////////////////////////////////////////////////////////////////////////////////////////// -service RemoveWalletPassword { +service Wallet { + rpc GetBalance (GetBalanceRequest) returns (GetBalanceReply) { + } + rpc SetWalletPassword (SetWalletPasswordRequest) returns (SetWalletPasswordReply) { + } rpc RemoveWalletPassword (RemoveWalletPasswordRequest) returns (RemoveWalletPasswordReply) { } + rpc LockWallet (LockWalletRequest) returns (LockWalletReply) { + } + rpc UnlockWallet (UnlockWalletRequest) returns (UnlockWalletReply) { + } } -message RemoveWalletPasswordRequest { - string password = 1; -} - -message RemoveWalletPasswordReply { +message GetBalanceRequest { } -/////////////////////////////////////////////////////////////////////////////////////////// -// SetWalletPassword -/////////////////////////////////////////////////////////////////////////////////////////// - -service SetWalletPassword { - rpc SetWalletPassword (SetWalletPasswordRequest) returns (SetWalletPasswordReply) { - } +message GetBalanceReply { + uint64 balance = 1; } message SetWalletPasswordRequest { @@ -161,13 +144,11 @@ message SetWalletPasswordRequest { message SetWalletPasswordReply { } -/////////////////////////////////////////////////////////////////////////////////////////// -// LockWallet -/////////////////////////////////////////////////////////////////////////////////////////// +message RemoveWalletPasswordRequest { + string password = 1; +} -service LockWallet { - rpc LockWallet (LockWalletRequest) returns (LockWalletReply) { - } +message RemoveWalletPasswordReply { } message LockWalletRequest { @@ -176,15 +157,6 @@ message LockWalletRequest { message LockWalletReply { } -/////////////////////////////////////////////////////////////////////////////////////////// -// UnlockWallet -/////////////////////////////////////////////////////////////////////////////////////////// - -service UnlockWallet { - rpc UnlockWallet (UnlockWalletRequest) returns (UnlockWalletReply) { - } -} - message UnlockWalletRequest { string password = 1; uint64 timeout = 2;