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

Fix trade protocol issues #4533

Merged
merged 10 commits into from
Sep 19, 2020
46 changes: 46 additions & 0 deletions core/src/main/java/bisq/core/app/AsciiLogo.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* 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.core.app;

import lombok.extern.slf4j.Slf4j;

@Slf4j
public class AsciiLogo {
public static void showAsciiLogo() {
log.info("\n\n" +
" ........ ...... \n" +
" .............. ...... \n" +
" ................. ...... \n" +
" ...... .......... .. ...... \n" +
" ...... ...... ...... ............... ..... ......... .......... \n" +
" ....... ........ .................. ..... ............. ............... \n" +
" ...... ........ .......... ....... ..... ...... ... ........ ....... \n" +
" ...... ..... ....... ..... ..... ..... ..... ...... \n" +
" ...... ... ... ...... ...... ..... ........... ...... ...... \n" +
" ...... ..... .... ...... ...... ..... ............ ..... ...... \n" +
" ...... ..... ...... ..... ........ ...... ...... \n" +
" ...... .... ... ...... ...... ..... .. ...... ...... ........ \n" +
" ........ .. ....... ................. ..... .............. ................... \n" +
" .......... ......... ............. ..... ............ ................. \n" +
" ...................... ..... .... .... ...... \n" +
" ................ ...... \n" +
" .... ...... \n" +
" ...... \n" +
"\n\n");
}
}
1 change: 1 addition & 0 deletions core/src/main/java/bisq/core/app/BisqExecutable.java
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ public void execute(String[] args) {
///////////////////////////////////////////////////////////////////////////////////////////

protected void doExecute() {
AsciiLogo.showAsciiLogo();
configUserThread();
CoreSetup.setup(config);
addCapabilities();
Expand Down
12 changes: 7 additions & 5 deletions core/src/main/java/bisq/core/btc/wallet/TxBroadcaster.java
Original file line number Diff line number Diff line change
Expand Up @@ -78,22 +78,24 @@ default void onTimeout(TxBroadcastTimeoutException exception) {
// Wallet.complete() method is called which is the case for all BSQ txs. We will work on a fix for that but that
// will take more time. In the meantime we reduce the timeout to 5 seconds to avoid that the trade protocol runs
// into a timeout when using BSQ for trade fee.
// For trade fee txs we set only 1 sec timeout for now.
// FIXME
private static final int DEFAULT_BROADCAST_TIMEOUT = 5;
private static Map<String, Timer> broadcastTimerMap = new HashMap<>();
private static final Map<String, Timer> broadcastTimerMap = new HashMap<>();

public static void broadcastTx(Wallet wallet, PeerGroup peerGroup, Transaction localTx, Callback callback) {
broadcastTx(wallet, peerGroup, localTx, callback, DEFAULT_BROADCAST_TIMEOUT);
}

public static void broadcastTx(Wallet wallet, PeerGroup peerGroup, Transaction tx, Callback callback, int delayInSec) {
public static void broadcastTx(Wallet wallet, PeerGroup peerGroup, Transaction tx, Callback callback, int timeOut) {
Timer timeoutTimer;
final String txId = tx.getTxId().toString();
if (!broadcastTimerMap.containsKey(txId)) {
timeoutTimer = UserThread.runAfter(() -> {
log.warn("Broadcast of tx {} not completed after {} sec.", txId, delayInSec);
log.warn("Broadcast of tx {} not completed after {} sec.", txId, timeOut);
stopAndRemoveTimer(txId);
UserThread.execute(() -> callback.onTimeout(new TxBroadcastTimeoutException(tx, delayInSec, wallet)));
}, delayInSec);
UserThread.execute(() -> callback.onTimeout(new TxBroadcastTimeoutException(tx, timeOut, wallet)));
}, timeOut);

broadcastTimerMap.put(txId, timeoutTimer);
} else {
Expand Down
5 changes: 4 additions & 1 deletion core/src/main/java/bisq/core/btc/wallet/WalletService.java
Original file line number Diff line number Diff line change
Expand Up @@ -342,11 +342,14 @@ public static void signTransactionInput(Wallet wallet,
// Broadcast tx
///////////////////////////////////////////////////////////////////////////////////////////


public void broadcastTx(Transaction tx, TxBroadcaster.Callback callback) {
TxBroadcaster.broadcastTx(wallet, walletsSetup.getPeerGroup(), tx, callback);
}

public void broadcastTx(Transaction tx, TxBroadcaster.Callback callback, int timeOut) {
TxBroadcaster.broadcastTx(wallet, walletsSetup.getPeerGroup(), tx, callback, timeOut);
}


///////////////////////////////////////////////////////////////////////////////////////////
// TransactionConfidence
Expand Down
6 changes: 4 additions & 2 deletions core/src/main/java/bisq/core/btc/wallet/WalletsManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -154,9 +154,11 @@ public void publishAndCommitBsqTx(Transaction tx, TxType txType, TxBroadcaster.C
// We need to create another instance, otherwise the tx would trigger an invalid state exception
// if it gets committed 2 times
// We clone before commit to avoid unwanted side effects
final Transaction clonedTx = btcWalletService.getClonedTransaction(tx);
Transaction clonedTx = btcWalletService.getClonedTransaction(tx);
btcWalletService.commitTx(clonedTx);
bsqWalletService.commitTx(tx, txType);
bsqWalletService.broadcastTx(tx, callback);

// We use a short timeout as there are issues with BSQ txs. See comment in TxBroadcaster
bsqWalletService.broadcastTx(tx, callback, 1);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ public void onFailure(TxBroadcastException exception) {
}
});
} else {
final BsqWalletService bsqWalletService = model.getBsqWalletService();
BsqWalletService bsqWalletService = model.getBsqWalletService();
Transaction preparedBurnFeeTx = model.getBsqWalletService().getPreparedTradeFeeTx(offer.getMakerFee());
Transaction txWithBsqFee = tradeWalletService.completeBsqTradingFeeTx(preparedBurnFeeTx,
fundingAddress,
Expand All @@ -126,32 +126,34 @@ public void onFailure(TxBroadcastException exception) {
// if it gets committed 2 times
tradeWalletService.commitTx(tradeWalletService.getClonedTransaction(signedTx));

// We use a short timeout as there are issues with BSQ txs. See comment in TxBroadcaster
bsqWalletService.broadcastTx(signedTx, new TxBroadcaster.Callback() {
@Override
public void onSuccess(@Nullable Transaction transaction) {
if (transaction != null) {
offer.setOfferFeePaymentTxId(transaction.getTxId().toString());
model.setTransaction(transaction);
log.debug("onSuccess, offerId={}, OFFER_FUNDING", id);
walletService.swapTradeEntryToAvailableEntry(id, AddressEntry.Context.OFFER_FUNDING);

log.debug("Successfully sent tx with id " + transaction.getTxId().toString());
model.getOffer().setState(Offer.State.OFFER_FEE_PAID);

complete();
}
}

@Override
public void onFailure(TxBroadcastException exception) {
log.error(exception.toString());
exception.printStackTrace();
offer.setErrorMessage("An error occurred.\n" +
"Error message:\n"
+ exception.getMessage());
failed(exception);
}
});
@Override
public void onSuccess(@Nullable Transaction transaction) {
if (transaction != null) {
offer.setOfferFeePaymentTxId(transaction.getTxId().toString());
model.setTransaction(transaction);
log.debug("onSuccess, offerId={}, OFFER_FUNDING", id);
walletService.swapTradeEntryToAvailableEntry(id, AddressEntry.Context.OFFER_FUNDING);

log.debug("Successfully sent tx with id " + transaction.getTxId().toString());
model.getOffer().setState(Offer.State.OFFER_FEE_PAID);

complete();
}
}

@Override
public void onFailure(TxBroadcastException exception) {
log.error(exception.toString());
exception.printStackTrace();
offer.setErrorMessage("An error occurred.\n" +
"Error message:\n"
+ exception.getMessage());
failed(exception);
}
},
1);
}
} catch (Throwable t) {
if (t instanceof DaoDisabledException) {
Expand Down
2 changes: 1 addition & 1 deletion core/src/main/java/bisq/core/setup/CoreSetup.java
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ public static void setup(Config config) {
private static void setupLog(Config config) {
String logPath = Paths.get(config.appDataDir.getPath(), "bisq").toString();
Log.setup(logPath);
log.info("\n\n\nLog files under: " + logPath);
log.info("Log files under: {}", logPath);
Utilities.printSysInfo();
Log.setLevel(Level.toLevel(config.logLevel));
}
Expand Down
19 changes: 5 additions & 14 deletions core/src/main/java/bisq/core/trade/protocol/TradeProtocol.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
import bisq.core.trade.Trade;
import bisq.core.trade.TradeManager;
import bisq.core.trade.messages.CounterCurrencyTransferStartedMessage;
import bisq.core.trade.messages.InputsForDepositTxRequest;
import bisq.core.trade.messages.MediatedPayoutTxPublishedMessage;
import bisq.core.trade.messages.MediatedPayoutTxSignatureMessage;
import bisq.core.trade.messages.PeerPublishedDelayedPayoutTxMessage;
Expand Down Expand Up @@ -357,15 +356,8 @@ private void sendAckMessage(@Nullable TradeMessage tradeMessage, boolean result,
return;

String tradeId = tradeMessage.getTradeId();
String sourceUid = "";
if (tradeMessage instanceof MailboxMessage) {
sourceUid = ((MailboxMessage) tradeMessage).getUid();
} else {
// For direct msg we don't have a mandatory uid so we need to cast to get it
if (tradeMessage instanceof InputsForDepositTxRequest) {
sourceUid = tradeMessage.getUid();
}
}
String sourceUid = tradeMessage.getUid();

AckMessage ackMessage = new AckMessage(processModel.getMyNodeAddress(),
AckMessageSourceType.TRADE_MESSAGE,
tradeMessage.getClass().getSimpleName(),
Expand All @@ -378,7 +370,6 @@ private void sendAckMessage(@Nullable TradeMessage tradeMessage, boolean result,
final NodeAddress peersNodeAddress = trade.getTradingPeerNodeAddress() != null ? trade.getTradingPeerNodeAddress() : processModel.getTempTradingPeerNodeAddress();
log.info("Send AckMessage for {} to peer {}. tradeId={}, sourceUid={}",
ackMessage.getSourceMsgClassName(), peersNodeAddress, tradeId, sourceUid);
String finalSourceUid = sourceUid;
processModel.getP2PService().sendEncryptedMailboxMessage(
peersNodeAddress,
processModel.getTradingPeer().getPubKeyRing(),
Expand All @@ -387,19 +378,19 @@ private void sendAckMessage(@Nullable TradeMessage tradeMessage, boolean result,
@Override
public void onArrived() {
log.info("AckMessage for {} arrived at peer {}. tradeId={}, sourceUid={}",
ackMessage.getSourceMsgClassName(), peersNodeAddress, tradeId, finalSourceUid);
ackMessage.getSourceMsgClassName(), peersNodeAddress, tradeId, sourceUid);
}

@Override
public void onStoredInMailbox() {
log.info("AckMessage for {} stored in mailbox for peer {}. tradeId={}, sourceUid={}",
ackMessage.getSourceMsgClassName(), peersNodeAddress, tradeId, finalSourceUid);
ackMessage.getSourceMsgClassName(), peersNodeAddress, tradeId, sourceUid);
}

@Override
public void onFault(String errorMessage) {
log.error("AckMessage for {} failed. Peer {}. tradeId={}, sourceUid={}, errorMessage={}",
ackMessage.getSourceMsgClassName(), peersNodeAddress, tradeId, finalSourceUid, errorMessage);
ackMessage.getSourceMsgClassName(), peersNodeAddress, tradeId, sourceUid, errorMessage);
}
}
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ protected void run() {
processModel.removeMailboxMessageAfterProcessing(trade);

// If we got already the confirmation we don't want to apply an earlier state
if (trade.getState() != Trade.State.BUYER_SAW_DEPOSIT_TX_IN_NETWORK)
if (trade.getState().ordinal() < Trade.State.BUYER_SAW_DEPOSIT_TX_IN_NETWORK.ordinal())
trade.setState(Trade.State.BUYER_RECEIVED_DEPOSIT_TX_PUBLISHED_MSG);

processModel.getBtcWalletService().swapTradeEntryToAvailableEntry(trade.getId(), AddressEntry.Context.RESERVED_FOR_TRADE);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ public void onFailure(TxBroadcastException exception) {
// if it gets committed 2 times
tradeWalletService.commitTx(tradeWalletService.getClonedTransaction(takeOfferFeeTx));

// We use a short timeout as there are issues with BSQ txs. See comment in TxBroadcaster
bsqWalletService.broadcastTx(takeOfferFeeTx,
new TxBroadcaster.Callback() {
@Override
Expand Down Expand Up @@ -104,7 +105,8 @@ public void onFailure(TxBroadcastException exception) {
log.warn("We got the onFailure callback called after the timeout has been triggered a complete().");
}
}
});
},
1);
}
} catch (Throwable t) {
failed(t);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ public void activate() {
if (DevEnv.isDevMode()) {
UserThread.runAfter(() -> {
amount.set("0.001");
price.set("0.008");
price.set("70000");
minAmount.set(amount.get());
onFocusOutPriceAsPercentageTextField(true, false);
applyMakerFee();
Expand Down