diff --git a/cli/src/main/java/bisq/cli/CliMain.java b/cli/src/main/java/bisq/cli/CliMain.java index 64bc959ba83..6790affe609 100644 --- a/cli/src/main/java/bisq/cli/CliMain.java +++ b/cli/src/main/java/bisq/cli/CliMain.java @@ -177,6 +177,14 @@ public static void run(String[] args) { out.println(network); return; } + case getdaostatus: { + if (new SimpleMethodOptionParser(args).parse().isForHelp()) { + out.println(client.getMethodHelp(method)); + return; + } + out.println(client.getDaoStatus()); + return; + } case getbalance: { var opts = new GetBalanceOptionParser(args).parse(); if (opts.isForHelp()) { @@ -866,6 +874,8 @@ private static void printHelp(OptionParser parser, @SuppressWarnings("SameParame stream.println(); stream.format(rowFormat, getnetwork.name(), "", "Get BTC network: mainnet, testnet3, or regtest"); stream.println(); + stream.format(rowFormat, getdaostatus.name(), "", "Get DAO synchronized status: true or false"); + stream.println(); stream.format(rowFormat, getbalance.name(), "[--currency-code=]", "Get server wallet balances"); stream.println(); stream.format(rowFormat, getaddressbalance.name(), "--address=", "Get server wallet address balance"); diff --git a/cli/src/main/java/bisq/cli/GrpcClient.java b/cli/src/main/java/bisq/cli/GrpcClient.java index 51e25db49f0..09185f56bb6 100644 --- a/cli/src/main/java/bisq/cli/GrpcClient.java +++ b/cli/src/main/java/bisq/cli/GrpcClient.java @@ -80,6 +80,10 @@ public String getNetwork() { return walletsServiceRequest.getNetwork(); } + public boolean getDaoStatus() { + return walletsServiceRequest.getDaoStatus(); + } + public BalancesInfo getBalances() { return walletsServiceRequest.getBalances(); } diff --git a/cli/src/main/java/bisq/cli/Method.java b/cli/src/main/java/bisq/cli/Method.java index a3109011484..d56e219a2ff 100644 --- a/cli/src/main/java/bisq/cli/Method.java +++ b/cli/src/main/java/bisq/cli/Method.java @@ -64,5 +64,6 @@ public enum Method { unlockwallet, unsettxfeerate, withdrawfunds, - stop + stop, + getdaostatus } diff --git a/cli/src/main/java/bisq/cli/request/WalletsServiceRequest.java b/cli/src/main/java/bisq/cli/request/WalletsServiceRequest.java index df772e35dcb..c880e1148d0 100644 --- a/cli/src/main/java/bisq/cli/request/WalletsServiceRequest.java +++ b/cli/src/main/java/bisq/cli/request/WalletsServiceRequest.java @@ -23,6 +23,7 @@ import bisq.proto.grpc.BtcBalanceInfo; import bisq.proto.grpc.GetAddressBalanceRequest; import bisq.proto.grpc.GetBalancesRequest; +import bisq.proto.grpc.GetDaoStatusRequest; import bisq.proto.grpc.GetFundingAddressesRequest; import bisq.proto.grpc.GetNetworkRequest; import bisq.proto.grpc.GetTransactionRequest; @@ -61,6 +62,11 @@ public String getNetwork() { return grpcStubs.walletsService.getNetwork(request).getNetwork(); } + public boolean getDaoStatus() { + var request = GetDaoStatusRequest.newBuilder().build(); + return grpcStubs.walletsService.getDaoStatus(request).getIsDaoStateReadyAndInSync(); + } + public BalancesInfo getBalances() { return getBalances(""); } diff --git a/core/src/main/java/bisq/core/api/CoreApi.java b/core/src/main/java/bisq/core/api/CoreApi.java index 635e37ec2ea..fcdd9659a40 100644 --- a/core/src/main/java/bisq/core/api/CoreApi.java +++ b/core/src/main/java/bisq/core/api/CoreApi.java @@ -374,6 +374,10 @@ public String getNetworkName() { return walletsService.getNetworkName(); } + public boolean isDaoStateReadyAndInSync() { + return walletsService.isDaoStateReadyAndInSync(); + } + public BalancesInfo getBalances(String currencyCode) { return walletsService.getBalances(currencyCode); } diff --git a/core/src/main/java/bisq/core/api/CoreWalletsService.java b/core/src/main/java/bisq/core/api/CoreWalletsService.java index 3ba7abadc3a..02446b5d708 100644 --- a/core/src/main/java/bisq/core/api/CoreWalletsService.java +++ b/core/src/main/java/bisq/core/api/CoreWalletsService.java @@ -40,6 +40,7 @@ import bisq.core.btc.wallet.BtcWalletService; import bisq.core.btc.wallet.TxBroadcaster; import bisq.core.btc.wallet.WalletsManager; +import bisq.core.dao.DaoFacade; import bisq.core.provider.fee.FeeService; import bisq.core.user.Preferences; import bisq.core.util.FormattingUtils; @@ -48,7 +49,6 @@ import bisq.common.Timer; import bisq.common.UserThread; -import bisq.common.handlers.ResultHandler; import bisq.common.util.SingleThreadExecutorUtils; import org.bitcoinj.core.Address; @@ -68,10 +68,7 @@ import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; import com.google.common.util.concurrent.FutureCallback; -import com.google.common.util.concurrent.Futures; -import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListeningExecutorService; -import com.google.common.util.concurrent.MoreExecutors; import org.bouncycastle.crypto.params.KeyParameter; @@ -81,7 +78,6 @@ import java.util.function.Function; import java.util.function.Predicate; import java.util.stream.Collectors; -import java.util.stream.Stream; import lombok.extern.slf4j.Slf4j; @@ -109,6 +105,7 @@ class CoreWalletsService { private final BtcWalletService btcWalletService; private final CoinFormatter btcFormatter; private final FeeService feeService; + private final DaoFacade daoFacade; private final Preferences preferences; @Nullable @@ -130,6 +127,7 @@ public CoreWalletsService(AppStartupState appStartupState, BtcWalletService btcWalletService, @Named(FormattingUtils.BTC_FORMATTER_KEY) CoinFormatter btcFormatter, FeeService feeService, + DaoFacade daoFacade, Preferences preferences) { this.appStartupState = appStartupState; this.coreContext = coreContext; @@ -141,6 +139,7 @@ public CoreWalletsService(AppStartupState appStartupState, this.btcWalletService = btcWalletService; this.btcFormatter = btcFormatter; this.feeService = feeService; + this.daoFacade = daoFacade; this.preferences = preferences; } @@ -166,6 +165,10 @@ String getNetworkName() { } } + boolean isDaoStateReadyAndInSync() { + return daoFacade.isDaoStateReadyAndInSync(); + } + BalancesInfo getBalances(String currencyCode) { verifyWalletCurrencyCodeIsValid(currencyCode); verifyWalletsAreAvailable(); diff --git a/core/src/main/resources/help/getdaostatus-help.txt b/core/src/main/resources/help/getdaostatus-help.txt new file mode 100644 index 00000000000..aa4ee700f22 --- /dev/null +++ b/core/src/main/resources/help/getdaostatus-help.txt @@ -0,0 +1,23 @@ +getdaostatus + +NAME +---- +getdaostatus - get DAO status + +SYNOPSIS +-------- +getdaostatus + +DESCRIPTION +----------- +Returns the operating status of the Bisq DAO: +true - DAO is ready and in sync +false - DAO is not ready + +At startup the status will return false until the DAO has completed synchronizing. +Trading operations should not be performed when the status is false. +While running, the status can be used to determine if DAO is in sync with the seed nodes. + +EXAMPLES +-------- +$ ./bisq-cli --password=xyz --port=9998 getdaostatus diff --git a/daemon/src/main/java/bisq/daemon/grpc/GrpcWalletsService.java b/daemon/src/main/java/bisq/daemon/grpc/GrpcWalletsService.java index 191c41a06f5..0b31b2ecdd0 100644 --- a/daemon/src/main/java/bisq/daemon/grpc/GrpcWalletsService.java +++ b/daemon/src/main/java/bisq/daemon/grpc/GrpcWalletsService.java @@ -31,6 +31,8 @@ import bisq.proto.grpc.GetFundingAddressesRequest; import bisq.proto.grpc.GetNetworkReply; import bisq.proto.grpc.GetNetworkRequest; +import bisq.proto.grpc.GetDaoStatusReply; +import bisq.proto.grpc.GetDaoStatusRequest; import bisq.proto.grpc.GetTransactionReply; import bisq.proto.grpc.GetTransactionRequest; import bisq.proto.grpc.GetTransactionsReply; @@ -114,6 +116,19 @@ public void getNetwork(GetNetworkRequest req, StreamObserver re } } + @Override + public void getDaoStatus(GetDaoStatusRequest req, StreamObserver responseObserver) { + try { + var reply = GetDaoStatusReply.newBuilder() + .setIsDaoStateReadyAndInSync(coreApi.isDaoStateReadyAndInSync()) + .build(); + responseObserver.onNext(reply); + responseObserver.onCompleted(); + } catch (Throwable cause) { + exceptionHandler.handleException(log, cause, responseObserver); + } + } + @Override public void getBalances(GetBalancesRequest req, StreamObserver responseObserver) { try { @@ -403,6 +418,7 @@ final Optional rateMeteringInterceptor() { .or(() -> Optional.of(CallRateMeteringInterceptor.valueOf( new HashMap<>() {{ put(getGetNetworkMethod().getFullMethodName(), new GrpcCallRateMeter(1, SECONDS)); + put(getGetDaoStatusMethod().getFullMethodName(), new GrpcCallRateMeter(1, SECONDS)); put(getGetBalancesMethod().getFullMethodName(), new GrpcCallRateMeter(1, SECONDS)); put(getGetAddressBalanceMethod().getFullMethodName(), new GrpcCallRateMeter(1, SECONDS)); put(getGetFundingAddressesMethod().getFullMethodName(), new GrpcCallRateMeter(1, SECONDS)); diff --git a/proto/src/main/proto/grpc.proto b/proto/src/main/proto/grpc.proto index c4da4756fb7..eb581c19b50 100644 --- a/proto/src/main/proto/grpc.proto +++ b/proto/src/main/proto/grpc.proto @@ -732,6 +732,9 @@ service Wallets { // Get the name of the BTC / BSQ network (mainnet, testnet3, or regtest). rpc GetNetwork (GetNetworkRequest) returns (GetNetworkReply) { } + // Get status of the DAO. + rpc GetDaoStatus (GetDaoStatusRequest) returns (GetDaoStatusReply) { + } // Get the Bisq wallet's current BSQ and BTC balances. rpc GetBalances (GetBalancesRequest) returns (GetBalancesReply) { } @@ -795,6 +798,13 @@ message GetNetworkReply { string network = 1; // The BTC network name (mainnet, testnet3, or regtest). } +message GetDaoStatusRequest { +} + +message GetDaoStatusReply { + bool is_dao_state_ready_and_in_sync = 1; +} + message GetBalancesRequest { string currency_code = 1; // The Bisq wallet currency (BSQ or BTC) for the balances request. }