Skip to content

Commit

Permalink
Merge pull request #5775 from chimp1984/bsq-swap-impl
Browse files Browse the repository at this point in the history
Bsq swap: Implementation [3]
  • Loading branch information
ripcurlx authored Nov 4, 2021
2 parents 6f41558 + 26e7541 commit da66ffe
Show file tree
Hide file tree
Showing 522 changed files with 20,000 additions and 3,700 deletions.
2 changes: 1 addition & 1 deletion apitest/scripts/trade-simulation-utils.sh
Original file line number Diff line number Diff line change
Expand Up @@ -458,7 +458,7 @@ delayconfirmpaymentreceived() {
}

# This is a large function that should be broken up if it ever makes sense to not treat a trade
# execution simulation as an atomic operation. But we are not testing api methods here, just
# execution simulation as an bsq swap operation. But we are not testing api methods here, just
# demonstrating how to use them to get through the trade protocol. It should work for any trade
# between Bob & Alice, as long as Alice is maker, Bob is taker, and the offer to be taken is the
# first displayed in Bob's getoffers command output.
Expand Down
6 changes: 4 additions & 2 deletions apitest/src/main/java/bisq/apitest/linux/BashCommand.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@

import lombok.extern.slf4j.Slf4j;

import org.jetbrains.annotations.NotNull;
import javax.annotation.Nullable;

import static bisq.apitest.config.ApiTestConfig.BASH_PATH_VALUE;
import static java.lang.management.ManagementFactory.getRuntimeMXBean;
Expand All @@ -33,7 +33,9 @@
public class BashCommand {

private int exitStatus = -1;
@Nullable
private String output;
@Nullable
private String error;

private final String command;
Expand Down Expand Up @@ -92,6 +94,7 @@ public int getExitStatus() {
}

// TODO return Optional<String>
@Nullable
public String getOutput() {
return this.output;
}
Expand All @@ -101,7 +104,6 @@ public String getError() {
return this.error;
}

@NotNull
private List<String> tokenizeSystemCommand() {
return new ArrayList<>() {{
add(BASH_PATH_VALUE);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,15 +57,13 @@ class SystemCommandExecutor {
private ThreadedStreamHandler errorStreamHandler;

public SystemCommandExecutor(final List<String> cmdOptions) {
if (log.isDebugEnabled())
log.debug("cmd options {}", cmdOptions.toString());

if (cmdOptions.isEmpty())
throw new IllegalStateException("No command params specified.");

if (cmdOptions.contains("sudo"))
throw new IllegalStateException("'sudo' commands are prohibited.");

log.trace("System cmd options {}", cmdOptions);
this.cmdOptions = cmdOptions;
}

Expand Down
10 changes: 4 additions & 6 deletions apitest/src/test/java/bisq/apitest/ApiTestCase.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@

package bisq.apitest;

import java.time.Duration;

import java.io.IOException;

import java.util.concurrent.ExecutionException;
Expand All @@ -32,9 +34,9 @@
import static bisq.apitest.config.BisqAppConfig.alicedaemon;
import static bisq.apitest.config.BisqAppConfig.arbdaemon;
import static bisq.apitest.config.BisqAppConfig.bobdaemon;
import static com.google.common.util.concurrent.Uninterruptibles.sleepUninterruptibly;
import static java.net.InetAddress.getLoopbackAddress;
import static java.util.Arrays.stream;
import static java.util.concurrent.TimeUnit.MILLISECONDS;



Expand Down Expand Up @@ -131,11 +133,7 @@ protected static void genBtcBlocksThenWait(int numBlocks, long wait) {
}

protected static void sleep(long ms) {
try {
MILLISECONDS.sleep(ms);
} catch (InterruptedException ignored) {
// empty
}
sleepUninterruptibly(Duration.ofMillis(ms));
}

protected final String testName(TestInfo testInfo) {
Expand Down
40 changes: 37 additions & 3 deletions apitest/src/test/java/bisq/apitest/method/MethodTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,20 @@
import java.util.function.Function;
import java.util.stream.Collectors;

import org.slf4j.Logger;

import javax.annotation.Nullable;

import static bisq.apitest.config.ApiTestRateMeterInterceptorConfig.getTestRateMeterInterceptorConfig;
import static java.lang.String.format;
import static java.nio.charset.StandardCharsets.UTF_8;
import static java.util.Arrays.stream;
import static org.junit.jupiter.api.Assertions.fail;



import bisq.apitest.ApiTestCase;
import bisq.apitest.linux.BashCommand;
import bisq.cli.GrpcClient;

public class MethodTest extends ApiTestCase {
Expand Down Expand Up @@ -144,14 +150,42 @@ protected bisq.core.payment.PaymentAccount createDummyBRLAccount(GrpcClient grpc
protected final bisq.core.payment.PaymentAccount createPaymentAccount(GrpcClient grpcClient, String jsonString) {
// Normally, we do asserts on the protos from the gRPC service, but in this
// case we need a bisq.core.payment.PaymentAccount so it can be cast to its
// sub type.
// sub-type.
var paymentAccount = grpcClient.createPaymentAccount(jsonString);
return bisq.core.payment.PaymentAccount.fromProto(paymentAccount, CORE_PROTO_RESOLVER);
}

// Static conveniences for test methods and test case fixture setups.

protected static String encodeToHex(String s) {
return Utilities.bytesAsHexString(s.getBytes(UTF_8));
}

protected void verifyNoLoggedNodeExceptions() {
var loggedExceptions = getNodeExceptionMessages();
if (loggedExceptions != null) {
String err = format("Exception(s) found in daemon log(s):%n%s", loggedExceptions);
fail(err);
}
}

protected void printNodeExceptionMessages(Logger log) {
var loggedExceptions = getNodeExceptionMessages();
if (loggedExceptions != null)
log.error("Exception(s) found in daemon log(s):\n{}", loggedExceptions);
}

@Nullable
protected static String getNodeExceptionMessages() {
var nodeLogsSpec = config.rootAppDataDir.getAbsolutePath() + "/bisq-BTC_REGTEST_*_dao/bisq.log";
var grep = "grep Exception " + nodeLogsSpec;
var bashCommand = new BashCommand(grep);
try {
bashCommand.run();
} catch (IOException | InterruptedException ex) {
fail("Bash command execution error: " + ex);
}
if (bashCommand.getError() == null)
return bashCommand.getOutput();
else
throw new IllegalStateException("Bash command execution error: " + bashCommand.getError());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,16 @@ public static void setUp() {
bobdaemon);
}

public static void createBsqSwapBsqPaymentAccounts() {
alicesBsqAcct = aliceClient.createCryptoCurrencyPaymentAccount("Alice's BsqSwap Account",
BSQ,
aliceClient.getUnusedBsqAddress(), // TODO refactor, bsq address not needed for atom acct
false);
bobsBsqAcct = bobClient.createCryptoCurrencyPaymentAccount("Bob's BsqSwap Account",
BSQ,
bobClient.getUnusedBsqAddress(), // TODO refactor, bsq address not needed for atom acct
false);
}

// Mkt Price Margin value of offer returned from server is scaled down by 10^-2.
protected final Function<Double, Double> scaledDownMktPriceMargin = (mktPriceMargin) ->
Expand Down
173 changes: 173 additions & 0 deletions apitest/src/test/java/bisq/apitest/method/offer/BsqSwapOfferTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/

package bisq.apitest.method.offer;

import bisq.proto.grpc.BsqSwapOfferInfo;

import lombok.extern.slf4j.Slf4j;

import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder;

import static bisq.apitest.config.ApiTestConfig.BSQ;
import static bisq.apitest.config.ApiTestConfig.BTC;
import static bisq.cli.TableFormat.formatBalancesTbls;
import static java.lang.String.format;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.fail;
import static protobuf.OfferDirection.BUY;

@Disabled
@Slf4j
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class BsqSwapOfferTest extends AbstractOfferTest {

@BeforeAll
public static void setUp() {
AbstractOfferTest.setUp();
createBsqSwapBsqPaymentAccounts();
}

@BeforeEach
public void generateBtcBlock() {
genBtcBlocksThenWait(1, 2000);
}

@Test
@Order(1)
public void testGetBalancesBeforeCreateOffers() {
var alicesBalances = aliceClient.getBalances();
log.debug("Alice's Before Trade Balance:\n{}", formatBalancesTbls(alicesBalances));
var bobsBalances = bobClient.getBalances();
log.debug("Bob's Before Trade Balance:\n{}", formatBalancesTbls(bobsBalances));
}

@Test
@Order(2)
public void testAliceCreateBsqSwapBuyOffer1() {
createBsqSwapOffer();
}

@Test
@Order(3)
public void testAliceCreateBsqSwapBuyOffer2() {
createBsqSwapOffer();
}

@Test
@Order(4)
public void testAliceCreateBsqSwapBuyOffer3() {
createBsqSwapOffer();
}

@Test
@Order(5)
public void testAliceCreateBsqSwapBuyOffer4() {
createBsqSwapOffer();
}

@Test
@Order(6)
public void testGetMyBsqSwapOffers() {
var offers = aliceClient.getMyBsqSwapBsqOffersSortedByDate();
assertEquals(4, offers.size());
}

@Test
@Order(7)
public void testGetAvailableBsqSwapOffers() {
var offers = bobClient.getBsqSwapOffersSortedByDate();
assertEquals(4, offers.size());
}

@Test
@Order(8)
public void testGetBalancesAfterCreateOffers() {
var alicesBalances = aliceClient.getBalances();
log.debug("Alice's After Trade Balance:\n{}", formatBalancesTbls(alicesBalances));
var bobsBalances = bobClient.getBalances();
log.debug("Bob's After Trade Balance:\n{}", formatBalancesTbls(bobsBalances));
}

private void createBsqSwapOffer() {
var bsqSwapOffer = aliceClient.createBsqSwapOffer(BUY.name(),
1_000_000L,
1_000_000L,
"0.00005",
alicesBsqAcct.getId());
log.debug("BsqSwap Sell BSQ (Buy BTC) OFFER:\n{}", bsqSwapOffer);
var newOfferId = bsqSwapOffer.getId();
assertNotEquals("", newOfferId);
assertEquals(BUY.name(), bsqSwapOffer.getDirection());
assertEquals(5_000, bsqSwapOffer.getPrice());
assertEquals(1_000_000L, bsqSwapOffer.getAmount());
assertEquals(1_000_000L, bsqSwapOffer.getMinAmount());
// assertEquals(alicesBsqAcct.getId(), atomicOffer.getMakerPaymentAccountId());
assertEquals(BSQ, bsqSwapOffer.getBaseCurrencyCode());
assertEquals(BTC, bsqSwapOffer.getCounterCurrencyCode());

testGetMyBsqSwapOffer(bsqSwapOffer);
testGetBsqSwapOffer(bsqSwapOffer);
}

private void testGetMyBsqSwapOffer(BsqSwapOfferInfo bsqSwapOfferInfo) {
int numFetchAttempts = 0;
while (true) {
try {
numFetchAttempts++;
var fetchedBsqSwapOffer = aliceClient.getMyBsqSwapOffer(bsqSwapOfferInfo.getId());
assertEquals(bsqSwapOfferInfo.getId(), fetchedBsqSwapOffer.getId());
log.debug("Alice found her (my) new bsq swap offer on attempt # {}.", numFetchAttempts);
break;
} catch (Exception ex) {
log.warn(ex.getMessage());

if (numFetchAttempts >= 9)
fail(format("Alice giving up on fetching her (my) bsq swap offer after %d attempts.", numFetchAttempts), ex);

sleep(1000);
}
}
}

private void testGetBsqSwapOffer(BsqSwapOfferInfo bsqSwapOfferInfo) {
int numFetchAttempts = 0;
while (true) {
try {
numFetchAttempts++;
var fetchedBsqSwapOffer = bobClient.getBsqSwapOffer(bsqSwapOfferInfo.getId());
assertEquals(bsqSwapOfferInfo.getId(), fetchedBsqSwapOffer.getId());
log.debug("Bob found new available bsq swap offer on attempt # {}.", numFetchAttempts);
break;
} catch (Exception ex) {
log.warn(ex.getMessage());

if (numFetchAttempts > 9)
fail(format("Bob gave up on fetching available bsq swap offer after %d attempts.", numFetchAttempts), ex);

sleep(1000);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
import static bisq.apitest.config.ApiTestConfig.BSQ;
import static bisq.core.btc.wallet.Restrictions.getDefaultBuyerSecurityDepositAsPercent;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static protobuf.OfferPayload.Direction.BUY;
import static protobuf.OfferDirection.BUY;

@Disabled
@Slf4j
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@
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 protobuf.OfferPayload.Direction.BUY;
import static protobuf.OfferPayload.Direction.SELL;
import static protobuf.OfferDirection.BUY;
import static protobuf.OfferDirection.SELL;

@Disabled
@Slf4j
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@
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 protobuf.OfferPayload.Direction.BUY;
import static protobuf.OfferPayload.Direction.SELL;
import static protobuf.OfferDirection.BUY;
import static protobuf.OfferDirection.SELL;

@Disabled
@Slf4j
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,8 @@
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 protobuf.OfferPayload.Direction.BUY;
import static protobuf.OfferPayload.Direction.SELL;
import static protobuf.OfferDirection.BUY;
import static protobuf.OfferDirection.SELL;

@SuppressWarnings("ConstantConditions")
@Disabled
Expand Down
Loading

0 comments on commit da66ffe

Please sign in to comment.