Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement and test new getbalance(s) api methods #4799

Merged
merged 10 commits into from
Dec 3, 2020
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() {
ghubstan marked this conversation as resolved.
Show resolved Hide resolved
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.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Persistence has had some changes to increase the persist frequency, might not need to wait this long

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've noticed significant improvement while testing the api on top of v1.5.0. I'll be checking what wait times I can reduce in apitest.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But I could not reduce that wait time without the test failing. There may be other wait times that can be reduced, like waiting for app startup & shutdown, but not this one.

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