Skip to content

Commit

Permalink
Implement and test new getbalance(s) api methods
Browse files Browse the repository at this point in the history
- Added three new methods to CLI:

      getbalances   ...	returns complete bsq and btc balance info
      getbsqbalance ...	returns complete bsq balance info
      getbtcbalance ...	returns complete btc balance info

      The old getbalance method is deprecated and will be removed
      if there is agreement to do that.

- Made the needed changes in the CLI's output formatting classes.

- Added new tests to existing BsqWalletTest, added new BtcWalletTest
  and WalletBalancesTest.

- Added disabled tests for funding a bsq wallet (todo in next PR).
  • Loading branch information
ghubstan committed Nov 13, 2020
1 parent 8dc1a74 commit 208a37b
Show file tree
Hide file tree
Showing 13 changed files with 706 additions and 54 deletions.
67 changes: 63 additions & 4 deletions apitest/src/test/java/bisq/apitest/method/MethodTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,19 @@

package bisq.apitest.method;

import bisq.proto.grpc.AddressBalanceInfo;
import bisq.proto.grpc.BalancesInfo;
import bisq.proto.grpc.BsqBalanceInfo;
import bisq.proto.grpc.BtcBalanceInfo;
import bisq.proto.grpc.CancelOfferRequest;
import bisq.proto.grpc.ConfirmPaymentReceivedRequest;
import bisq.proto.grpc.ConfirmPaymentStartedRequest;
import bisq.proto.grpc.CreatePaymentAccountRequest;
import bisq.proto.grpc.GetAddressBalanceRequest;
import bisq.proto.grpc.GetBalanceRequest;
import bisq.proto.grpc.GetBalancesRequest;
import bisq.proto.grpc.GetBsqBalancesRequest;
import bisq.proto.grpc.GetBtcBalancesRequest;
import bisq.proto.grpc.GetFundingAddressesRequest;
import bisq.proto.grpc.GetOfferRequest;
import bisq.proto.grpc.GetPaymentAccountsRequest;
Expand All @@ -33,6 +41,7 @@
import bisq.proto.grpc.OfferInfo;
import bisq.proto.grpc.RegisterDisputeAgentRequest;
import bisq.proto.grpc.RemoveWalletPasswordRequest;
import bisq.proto.grpc.SendBsqRequest;
import bisq.proto.grpc.SetWalletPasswordRequest;
import bisq.proto.grpc.TakeOfferRequest;
import bisq.proto.grpc.TradeInfo;
Expand Down Expand Up @@ -104,12 +113,25 @@ public static void startSupportingApps(boolean registerDisputeAgents,

// Convenience methods for building gRPC request objects

@Deprecated
protected final GetBalanceRequest createBalanceRequest() {
return GetBalanceRequest.newBuilder().build();
}

protected final GetUnusedBsqAddressRequest createGetUnusedBsqAddressRequest() {
return GetUnusedBsqAddressRequest.newBuilder().build();
protected final GetBalancesRequest createGetBalancesRequest() {
return GetBalancesRequest.newBuilder().build();
}

protected final GetAddressBalanceRequest createGetAddressBalanceRequest(String address) {
return GetAddressBalanceRequest.newBuilder().setAddress(address).build();
}

protected final GetBsqBalancesRequest createGetBsqBalancesRequest() {
return GetBsqBalancesRequest.newBuilder().build();
}

protected final GetBtcBalancesRequest createBtcBalancesRequest() {
return GetBtcBalancesRequest.newBuilder().build();
}

protected final SetWalletPasswordRequest createSetWalletPasswordRequest(String password) {
Expand All @@ -132,6 +154,14 @@ protected final LockWalletRequest createLockWalletRequest() {
return LockWalletRequest.newBuilder().build();
}

protected final GetUnusedBsqAddressRequest createGetUnusedBsqAddressRequest() {
return GetUnusedBsqAddressRequest.newBuilder().build();
}

protected final SendBsqRequest createSendBsqRequest(String address, double amount) {
return SendBsqRequest.newBuilder().setAddress(address).setAmount(amount).build();
}

protected final GetFundingAddressesRequest createGetFundingAddressesRequest() {
return GetFundingAddressesRequest.newBuilder().build();
}
Expand All @@ -148,8 +178,12 @@ protected final CancelOfferRequest createCancelOfferRequest(String offerId) {
return CancelOfferRequest.newBuilder().setId(offerId).build();
}

protected final TakeOfferRequest createTakeOfferRequest(String offerId, String paymentAccountId) {
return TakeOfferRequest.newBuilder().setOfferId(offerId).setPaymentAccountId(paymentAccountId).build();
protected final TakeOfferRequest createTakeOfferRequest(String offerId,
String paymentAccountId) {
return TakeOfferRequest.newBuilder()
.setOfferId(offerId)
.setPaymentAccountId(paymentAccountId)
.build();
}

protected final GetTradeRequest createGetTradeRequest(String tradeId) {
Expand Down Expand Up @@ -179,10 +213,27 @@ protected final WithdrawFundsRequest createWithdrawFundsRequest(String tradeId,

// Convenience methods for calling frequently used & thoroughly tested gRPC services.

@Deprecated
protected final long getBalance(BisqAppConfig bisqAppConfig) {
return grpcStubs(bisqAppConfig).walletsService.getBalance(createBalanceRequest()).getBalance();
}

protected final BalancesInfo getBalances(BisqAppConfig bisqAppConfig) {
return grpcStubs(bisqAppConfig).walletsService.getBalances(createGetBalancesRequest()).getBalances();
}

protected final BsqBalanceInfo getBsqBalances(BisqAppConfig bisqAppConfig) {
return grpcStubs(bisqAppConfig).walletsService.getBsqBalances(createGetBsqBalancesRequest()).getBsqBalanceInfo();
}

protected final BtcBalanceInfo getBtcBalances(BisqAppConfig bisqAppConfig) {
return grpcStubs(bisqAppConfig).walletsService.getBtcBalances(createBtcBalancesRequest()).getBtcBalanceInfo();
}

protected final AddressBalanceInfo getAddressBalance(BisqAppConfig bisqAppConfig, String address) {
return grpcStubs(bisqAppConfig).walletsService.getAddressBalance(createGetAddressBalanceRequest(address)).getAddressBalanceInfo();
}

protected final void unlockWallet(BisqAppConfig bisqAppConfig, String password, long timeout) {
//noinspection ResultOfMethodCallIgnored
grpcStubs(bisqAppConfig).walletsService.unlockWallet(createUnlockWalletRequest(password, timeout));
Expand All @@ -193,6 +244,14 @@ protected final void lockWallet(BisqAppConfig bisqAppConfig) {
grpcStubs(bisqAppConfig).walletsService.lockWallet(createLockWalletRequest());
}

protected final String getUnusedBsqAddress(BisqAppConfig bisqAppConfig) {
return grpcStubs(bisqAppConfig).walletsService.getUnusedBsqAddress(createGetUnusedBsqAddressRequest()).getAddress();
}

protected final void sendBsq(BisqAppConfig bisqAppConfig, String address, double amount) {
grpcStubs(bisqAppConfig).walletsService.sendBsq(createSendBsqRequest(address, amount));
}

protected final String getUnusedBtcAddress(BisqAppConfig bisqAppConfig) {
//noinspection OptionalGetWithoutIsPresent
return grpcStubs(bisqAppConfig).walletsService.getFundingAddresses(createGetFundingAddressesRequest())
Expand Down
188 changes: 185 additions & 3 deletions apitest/src/test/java/bisq/apitest/method/wallet/BsqWalletTest.java
Original file line number Diff line number Diff line change
@@ -1,43 +1,74 @@
package bisq.apitest.method.wallet;

import bisq.proto.grpc.BsqBalanceInfo;

import org.bitcoinj.core.LegacyAddress;
import org.bitcoinj.core.NetworkParameters;

import lombok.extern.slf4j.Slf4j;

import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInfo;
import org.junit.jupiter.api.TestMethodOrder;

import static bisq.apitest.Scaffold.BitcoinCoreApp.bitcoind;
import static bisq.apitest.config.BisqAppConfig.alicedaemon;
import static bisq.apitest.config.BisqAppConfig.arbdaemon;
import static bisq.apitest.config.BisqAppConfig.bobdaemon;
import static bisq.apitest.config.BisqAppConfig.seednode;
import static bisq.cli.TableFormat.formatBsqBalanceInfoTbl;
import static org.bitcoinj.core.NetworkParameters.PAYMENT_PROTOCOL_ID_MAINNET;
import static org.bitcoinj.core.NetworkParameters.PAYMENT_PROTOCOL_ID_REGTEST;
import static org.bitcoinj.core.NetworkParameters.PAYMENT_PROTOCOL_ID_TESTNET;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.MethodOrderer.OrderAnnotation;



import bisq.apitest.config.BisqAppConfig;
import bisq.apitest.method.MethodTest;

// @Disabled
@Disabled
@Slf4j
@TestMethodOrder(OrderAnnotation.class)
public class BsqWalletTest extends MethodTest {

// Alice's regtest BSQ wallet is initialized with 1,000,000 BSQ.
private static final bisq.core.api.model.BsqBalanceInfo ALICES_INITIAL_BSQ_BALANCES =
expectedBsqBalanceModel(100000000,
0,
0,
0,
0,
0);

// Bob's regtest BSQ wallet is initialized with 1,500,000 BSQ.
private static final bisq.core.api.model.BsqBalanceInfo BOBS_INITIAL_BSQ_BALANCES =
expectedBsqBalanceModel(150000000,
0,
0,
0,
0,
0);

private static final double SEND_BSQ_AMOUNT = 25000.50;

@BeforeAll
public static void setUp() {
startSupportingApps(false,
true,
bitcoind,
seednode,
alicedaemon);
arbdaemon,
alicedaemon,
bobdaemon);
}

@Test
Expand All @@ -52,13 +83,164 @@ public void testGetUnusedBsqAddress() {
NetworkParameters networkParameters = LegacyAddress.getParametersFromAddress(address.substring(1));
String addressNetwork = networkParameters.getPaymentProtocolId();
assertNotEquals(PAYMENT_PROTOCOL_ID_MAINNET, addressNetwork);
// TODO Fix bug(?) causing the regtest bsq address network to be evaluated as 'testnet' here.
// TODO Fix bug causing the regtest bsq address network to be evaluated as 'testnet' here.
assertTrue(addressNetwork.equals(PAYMENT_PROTOCOL_ID_TESTNET)
|| addressNetwork.equals(PAYMENT_PROTOCOL_ID_REGTEST));
}

@Test
@Order(2)
public void testInitialBsqBalances(final TestInfo testInfo) {
BsqBalanceInfo alicesBsqBalances = getBsqBalances(alicedaemon);
log.info("{} -> Alice's BSQ Initial Balances -> \n{}",
testName(testInfo),
formatBsqBalanceInfoTbl(alicesBsqBalances));
verifyBsqBalances(ALICES_INITIAL_BSQ_BALANCES, alicesBsqBalances);

BsqBalanceInfo bobsBsqBalances = getBsqBalances(bobdaemon);
log.info("{} -> Bob's BSQ Initial Balances -> \n{}",
testName(testInfo),
formatBsqBalanceInfoTbl(bobsBsqBalances));
verifyBsqBalances(BOBS_INITIAL_BSQ_BALANCES, bobsBsqBalances);
}

@Disabled // TODO
@Test
@Order(3)
public void testSendBsqAndCheckBalancesBeforeGeneratingBtcBlock(final TestInfo testInfo) {
String bobsBsqAddress = getUnusedBsqAddress(bobdaemon);
sendBsq(alicedaemon, bobsBsqAddress, SEND_BSQ_AMOUNT);
sleep(2000);

BsqBalanceInfo alicesBsqBalances = getBsqBalances(alicedaemon);
BsqBalanceInfo bobsBsqBalances = waitForNonZeroUnverifiedBalance(bobdaemon);

log.info("BSQ Balances Before BTC Block Gen...");
printBobAndAliceBsqBalances(testInfo,
bobsBsqBalances,
alicesBsqBalances,
alicedaemon);

verifyBsqBalances(expectedBsqBalanceModel(150000000,
2500050,
0,
0,
0,
0),
bobsBsqBalances);

verifyBsqBalances(expectedBsqBalanceModel(97499950,
97499950,
97499950,
0,
0,
0),
alicesBsqBalances);
}

@Disabled // TODO
@Test
@Order(4)
public void testBalancesAfterSendingBsqAndGeneratingBtcBlock(final TestInfo testInfo) {
// There is a wallet persist delay; we have to
// wait for both wallets to be saved to disk.
genBtcBlocksThenWait(1, 4000);

BsqBalanceInfo alicesBsqBalances = getBsqBalances(alicedaemon);
BsqBalanceInfo bobsBsqBalances = waitForNewAvailableConfirmedBalance(bobdaemon, 150000000);

log.info("See Available Confirmed BSQ Balances...");
printBobAndAliceBsqBalances(testInfo,
bobsBsqBalances,
alicesBsqBalances,
alicedaemon);

verifyBsqBalances(expectedBsqBalanceModel(152500050,
0,
0,
0,
0,
0),
bobsBsqBalances);

verifyBsqBalances(expectedBsqBalanceModel(97499950,
0,
0,
0,
0,
0),
alicesBsqBalances);
}

@AfterAll
public static void tearDown() {
tearDownScaffold();
}

private void verifyBsqBalances(bisq.core.api.model.BsqBalanceInfo expected,
bisq.proto.grpc.BsqBalanceInfo actual) {
assertEquals(expected.getAvailableConfirmedBalance(), actual.getAvailableConfirmedBalance());
assertEquals(expected.getUnverifiedBalance(), actual.getUnverifiedBalance());
assertEquals(expected.getUnconfirmedChangeBalance(), actual.getUnconfirmedChangeBalance());
assertEquals(expected.getLockedForVotingBalance(), actual.getLockedForVotingBalance());
assertEquals(expected.getLockupBondsBalance(), actual.getLockupBondsBalance());
assertEquals(expected.getUnlockingBondsBalance(), actual.getUnlockingBondsBalance());
}

private BsqBalanceInfo waitForNonZeroUnverifiedBalance(BisqAppConfig daemon) {
// A BSQ recipient needs to wait for her daemon to detect a new tx.
// Loop here until her unverifiedBalance != 0, or give up after 15 seconds.
// A slow test is preferred over a flaky test.
BsqBalanceInfo bsqBalance = getBsqBalances(daemon);
for (int numRequests = 1; numRequests <= 15 && bsqBalance.getUnverifiedBalance() == 0; numRequests++) {
sleep(1000);
bsqBalance = getBsqBalances(daemon);
}
return bsqBalance;
}

private BsqBalanceInfo waitForNewAvailableConfirmedBalance(BisqAppConfig daemon,
long staleBalance) {
BsqBalanceInfo bsqBalance = getBsqBalances(daemon);
for (int numRequests = 1;
numRequests <= 15 && bsqBalance.getAvailableConfirmedBalance() == staleBalance;
numRequests++) {
sleep(1000);
bsqBalance = getBsqBalances(daemon);
}
return bsqBalance;
}

@SuppressWarnings("SameParameterValue")
private void printBobAndAliceBsqBalances(final TestInfo testInfo,
BsqBalanceInfo bobsBsqBalances,
BsqBalanceInfo alicesBsqBalances,
BisqAppConfig senderApp) {
log.info("{} -> Bob's BSQ Balances After {} {} BSQ-> \n{}",
testName(testInfo),
senderApp.equals(bobdaemon) ? "Sending" : "Receiving",
SEND_BSQ_AMOUNT,
formatBsqBalanceInfoTbl(bobsBsqBalances));

log.info("{} -> Alice's Balances After {} {} BSQ-> \n{}",
testName(testInfo),
senderApp.equals(alicedaemon) ? "Sending" : "Receiving",
SEND_BSQ_AMOUNT,
formatBsqBalanceInfoTbl(alicesBsqBalances));
}

@SuppressWarnings("SameParameterValue")
private static bisq.core.api.model.BsqBalanceInfo expectedBsqBalanceModel(long availableConfirmedBalance,
long unverifiedBalance,
long unconfirmedChangeBalance,
long lockedForVotingBalance,
long lockupBondsBalance,
long unlockingBondsBalance) {
return bisq.core.api.model.BsqBalanceInfo.valueOf(availableConfirmedBalance,
unverifiedBalance,
unconfirmedChangeBalance,
lockedForVotingBalance,
lockupBondsBalance,
unlockingBondsBalance);
}
}
Loading

0 comments on commit 208a37b

Please sign in to comment.