From bd8e30c708e86ab20fb29824525d874c7ca13c30 Mon Sep 17 00:00:00 2001 From: sqrrm Date: Tue, 17 Dec 2019 11:45:57 +0100 Subject: [PATCH 1/7] Add shortcut to move failed trade to pending trades --- .../java/bisq/core/trade/TradeManager.java | 36 +++++++++++-------- .../trade/failed/FailedTradesManager.java | 11 ++++++ .../resources/i18n/displayStrings.properties | 2 ++ .../failedtrades/FailedTradesDataModel.java | 3 ++ .../failedtrades/FailedTradesView.java | 32 +++++++++++++++++ 5 files changed, 70 insertions(+), 14 deletions(-) diff --git a/core/src/main/java/bisq/core/trade/TradeManager.java b/core/src/main/java/bisq/core/trade/TradeManager.java index 5aad36e4fff..5d43da88cfd 100644 --- a/core/src/main/java/bisq/core/trade/TradeManager.java +++ b/core/src/main/java/bisq/core/trade/TradeManager.java @@ -225,6 +225,7 @@ public TradeManager(User user, } } }); + failedTradesManager.setUnfailTradeCallback(this::unfailTrade); } @Override @@ -298,20 +299,20 @@ private void initPendingTrades() { tradesWithoutDepositTx.add(trade); } - try { - DelayedPayoutTxValidation.validatePayoutTx(trade, - trade.getDelayedPayoutTx(), - daoFacade, - btcWalletService); - } catch (DelayedPayoutTxValidation.DonationAddressException | - DelayedPayoutTxValidation.InvalidTxException | - DelayedPayoutTxValidation.InvalidLockTimeException | - DelayedPayoutTxValidation.MissingDelayedPayoutTxException e) { - // We move it to failed trades so it cannot be continued. - log.warn("We move the trade with ID '{}' to failed trades because of exception {}", - trade.getId(), e.getMessage()); - addTradeToFailedTradesList.add(trade); - } + try { + DelayedPayoutTxValidation.validatePayoutTx(trade, + trade.getDelayedPayoutTx(), + daoFacade, + btcWalletService); + } catch (DelayedPayoutTxValidation.DonationAddressException | + DelayedPayoutTxValidation.InvalidTxException | + DelayedPayoutTxValidation.InvalidLockTimeException | + DelayedPayoutTxValidation.MissingDelayedPayoutTxException e) { + // We move it to failed trades so it cannot be continued. + log.warn("We move the trade with ID '{}' to failed trades because of exception {}", + trade.getId(), e.getMessage()); + addTradeToFailedTradesList.add(trade); + } } ); @@ -602,6 +603,13 @@ public void addTradeToFailedTrades(Trade trade) { cleanUpAddressEntries(); } + // If trade still has funds locked up it might come back from failed trades + private void unfailTrade(Trade trade) { + if (!tradableList.contains(trade)) { + tradableList.add(trade); + } + } + // If trade is in preparation (if taker role: before taker fee is paid; both roles: before deposit published) // we just remove the trade from our list. We don't store those trades. public void removePreparedTrade(Trade trade) { diff --git a/core/src/main/java/bisq/core/trade/failed/FailedTradesManager.java b/core/src/main/java/bisq/core/trade/failed/FailedTradesManager.java index 7733de0ff31..ab771bb4bf2 100644 --- a/core/src/main/java/bisq/core/trade/failed/FailedTradesManager.java +++ b/core/src/main/java/bisq/core/trade/failed/FailedTradesManager.java @@ -33,11 +33,14 @@ import javafx.collections.ObservableList; import java.util.Optional; +import java.util.function.Consumer; import java.util.stream.Stream; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import lombok.Setter; + public class FailedTradesManager implements PersistedDataHost { private static final Logger log = LoggerFactory.getLogger(FailedTradesManager.class); private TradableList failedTrades; @@ -46,6 +49,8 @@ public class FailedTradesManager implements PersistedDataHost { private final BtcWalletService btcWalletService; private final Storage> tradableListStorage; private final DumpDelayedPayoutTx dumpDelayedPayoutTx; + @Setter + private Consumer unfailTradeCallback; @Inject public FailedTradesManager(KeyRing keyRing, @@ -96,4 +101,10 @@ public Stream getTradesStreamWithFundsLockedIn() { return failedTrades.stream() .filter(Trade::isFundsLockedIn); } + + public void unfailTrade(Trade trade) { + if (unfailTradeCallback == null) return; + unfailTradeCallback.accept(trade); + failedTrades.remove(trade); + } } diff --git a/core/src/main/resources/i18n/displayStrings.properties b/core/src/main/resources/i18n/displayStrings.properties index dcfaed095f1..66609c30e52 100644 --- a/core/src/main/resources/i18n/displayStrings.properties +++ b/core/src/main/resources/i18n/displayStrings.properties @@ -859,6 +859,8 @@ portfolio.closed.ticketClosed=Arbitrated portfolio.closed.mediationTicketClosed=Mediated portfolio.closed.canceled=Canceled portfolio.failed.Failed=Failed +portfolio.failed.unfail=Do you want to move this trade back to pending trades? \ + Only do this if you need to open a support ticket. #################################################################### diff --git a/desktop/src/main/java/bisq/desktop/main/portfolio/failedtrades/FailedTradesDataModel.java b/desktop/src/main/java/bisq/desktop/main/portfolio/failedtrades/FailedTradesDataModel.java index ca971fe061f..048a643962e 100644 --- a/desktop/src/main/java/bisq/desktop/main/portfolio/failedtrades/FailedTradesDataModel.java +++ b/desktop/src/main/java/bisq/desktop/main/portfolio/failedtrades/FailedTradesDataModel.java @@ -74,4 +74,7 @@ private void applyList() { list.sort((o1, o2) -> o2.getTrade().getDate().compareTo(o1.getTrade().getDate())); } + public void unfailTrade(Trade trade) { + failedTradesManager.unfailTrade(trade); + } } diff --git a/desktop/src/main/java/bisq/desktop/main/portfolio/failedtrades/FailedTradesView.java b/desktop/src/main/java/bisq/desktop/main/portfolio/failedtrades/FailedTradesView.java index 940feda4c63..fd3f0121c82 100644 --- a/desktop/src/main/java/bisq/desktop/main/portfolio/failedtrades/FailedTradesView.java +++ b/desktop/src/main/java/bisq/desktop/main/portfolio/failedtrades/FailedTradesView.java @@ -21,22 +21,31 @@ import bisq.desktop.common.view.FxmlView; import bisq.desktop.components.AutoTooltipLabel; import bisq.desktop.components.HyperlinkWithIcon; +import bisq.desktop.main.overlays.popups.Popup; import bisq.desktop.main.overlays.windows.TradeDetailsWindow; import bisq.core.locale.Res; +import bisq.core.trade.Trade; + +import bisq.common.util.Utilities; import javax.inject.Inject; import javafx.fxml.FXML; +import javafx.scene.Scene; import javafx.scene.control.TableCell; import javafx.scene.control.TableColumn; import javafx.scene.control.TableView; import javafx.scene.control.Tooltip; +import javafx.scene.input.KeyCode; +import javafx.scene.input.KeyEvent; import javafx.scene.layout.VBox; import javafx.beans.property.ReadOnlyObjectWrapper; +import javafx.event.EventHandler; + import javafx.collections.transformation.SortedList; import javafx.util.Callback; @@ -53,6 +62,8 @@ public class FailedTradesView extends ActivatableViewAndModel sortedList; + private EventHandler keyEventEventHandler; + private Scene scene; @Inject public FailedTradesView(FailedTradesViewModel model, TradeDetailsWindow tradeDetailsWindow) { @@ -95,10 +106,28 @@ public void initialize() { dateColumn.setSortType(TableColumn.SortType.DESCENDING); tableView.getSortOrder().add(dateColumn); + keyEventEventHandler = keyEvent -> { + if (Utilities.isAltOrCtrlPressed(KeyCode.Y, keyEvent)) { + new Popup().warning(Res.get("portfolio.failed.unfail")) + .onAction(this::onUnfail) + .show(); + } + }; + + } + + private void onUnfail() { + Trade trade = sortedList.get(tableView.getSelectionModel().getFocusedIndex()).getTrade(); + model.dataModel.unfailTrade(trade); + } @Override protected void activate() { + scene = root.getScene(); + if (scene != null) { + scene.addEventHandler(KeyEvent.KEY_RELEASED, keyEventEventHandler); + } sortedList = new SortedList<>(model.getList()); sortedList.comparatorProperty().bind(tableView.comparatorProperty()); tableView.setItems(sortedList); @@ -106,6 +135,9 @@ protected void activate() { @Override protected void deactivate() { + if (scene != null) { + scene.removeEventHandler(KeyEvent.KEY_RELEASED, keyEventEventHandler); + } sortedList.comparatorProperty().unbind(); } From 817819dc51ec1adb4311cd46f8869f5f1f22fe44 Mon Sep 17 00:00:00 2001 From: sqrrm Date: Fri, 10 Apr 2020 16:25:05 +0200 Subject: [PATCH 2/7] Reattach addresses when unfailing trade --- .../core/btc/wallet/BtcWalletService.java | 7 ++ .../java/bisq/core/trade/TradeManager.java | 28 ++++++- .../main/java/bisq/core/trade/TradeUtils.java | 79 +++++++++++++++++++ .../trade/failed/FailedTradesManager.java | 33 ++++++-- .../resources/i18n/displayStrings.properties | 7 +- .../failedtrades/FailedTradesDataModel.java | 4 + .../failedtrades/FailedTradesView.java | 18 ++++- 7 files changed, 165 insertions(+), 11 deletions(-) create mode 100644 core/src/main/java/bisq/core/trade/TradeUtils.java diff --git a/core/src/main/java/bisq/core/btc/wallet/BtcWalletService.java b/core/src/main/java/bisq/core/btc/wallet/BtcWalletService.java index ce5d2433ab4..3bb4721b17a 100644 --- a/core/src/main/java/bisq/core/btc/wallet/BtcWalletService.java +++ b/core/src/main/java/bisq/core/btc/wallet/BtcWalletService.java @@ -598,6 +598,13 @@ public AddressEntry getNewAddressEntry(String offerId, AddressEntry.Context cont return entry; } + public AddressEntry recoverAddressEntry(String offerId, String address, AddressEntry.Context context) { + var available = findAddressEntry(address, AddressEntry.Context.AVAILABLE); + if (!available.isPresent()) + return null; + return addressEntryList.swapAvailableToAddressEntryWithOfferId(available.get(), context, offerId); + } + private AddressEntry getOrCreateAddressEntry(AddressEntry.Context context, Optional addressEntry) { if (addressEntry.isPresent()) { return addressEntry.get(); diff --git a/core/src/main/java/bisq/core/trade/TradeManager.java b/core/src/main/java/bisq/core/trade/TradeManager.java index 5d43da88cfd..32eb8916cd0 100644 --- a/core/src/main/java/bisq/core/trade/TradeManager.java +++ b/core/src/main/java/bisq/core/trade/TradeManager.java @@ -64,6 +64,8 @@ import bisq.common.proto.network.NetworkEnvelope; import bisq.common.proto.persistable.PersistedDataHost; import bisq.common.storage.Storage; +import bisq.common.util.Tuple2; +import bisq.common.util.Utilities; import org.bitcoinj.core.AddressFormatException; import org.bitcoinj.core.Coin; @@ -89,6 +91,7 @@ import java.util.ArrayList; import java.util.Date; import java.util.List; +import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.UUID; @@ -604,12 +607,35 @@ public void addTradeToFailedTrades(Trade trade) { } // If trade still has funds locked up it might come back from failed trades - private void unfailTrade(Trade trade) { + // Aborts unfailing if the address entries needed are not available + private boolean unfailTrade(Trade trade) { + if (!recoverAddresses(trade)) { + log.warn("Failed to recover address during unfail trade"); + return false; + } + if (!tradableList.contains(trade)) { tradableList.add(trade); } + return true; + } + + // The trade is added to pending trades if the associated address entries are AVAILABLE and + // the relevant entries are changed, otherwise it's not added and no address entries are changed + private boolean recoverAddresses(Trade trade) { + // Find addresses associated with this trade. + var entries = TradeUtils.getAvailableAddresses(trade, btcWalletService, keyRing); + if (entries == null) + return false; + + btcWalletService.recoverAddressEntry(trade.getId(), entries.first, + AddressEntry.Context.MULTI_SIG); + btcWalletService.recoverAddressEntry(trade.getId(), entries.second, + AddressEntry.Context.TRADE_PAYOUT); + return true; } + // If trade is in preparation (if taker role: before taker fee is paid; both roles: before deposit published) // we just remove the trade from our list. We don't store those trades. public void removePreparedTrade(Trade trade) { diff --git a/core/src/main/java/bisq/core/trade/TradeUtils.java b/core/src/main/java/bisq/core/trade/TradeUtils.java new file mode 100644 index 00000000000..10a5da8fdf8 --- /dev/null +++ b/core/src/main/java/bisq/core/trade/TradeUtils.java @@ -0,0 +1,79 @@ +/* + * 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 . + */ + +package bisq.core.trade; + +import bisq.core.btc.wallet.BtcWalletService; + +import bisq.common.crypto.KeyRing; +import bisq.common.util.Tuple2; +import bisq.common.util.Utilities; + +import java.util.Objects; + +public class TradeUtils { + + // Returns if both are AVAILABLE, otherwise null + static Tuple2 getAvailableAddresses(Trade trade, BtcWalletService btcWalletService, + KeyRing keyRing) { + var addresses = getTradeAddresses(trade, btcWalletService, keyRing); + if (addresses == null) + return null; + + if (btcWalletService.getAvailableAddressEntries().stream() + .noneMatch(e -> Objects.equals(e.getAddressString(), addresses.first))) + return null; + if (btcWalletService.getAvailableAddressEntries().stream() + .noneMatch(e -> Objects.equals(e.getAddressString(), addresses.second))) + return null; + + return new Tuple2<>(addresses.first, addresses.second); + } + + // Returns addresses as strings if they're known by the wallet + public static Tuple2 getTradeAddresses(Trade trade, BtcWalletService btcWalletService, + KeyRing keyRing) { + var contract = trade.getContract(); + if (contract == null) + return null; + + // Get multisig address + var isMyRoleBuyer = contract.isMyRoleBuyer(keyRing.getPubKeyRing()); + var multiSigPubKey = isMyRoleBuyer ? contract.getBuyerMultiSigPubKey() : contract.getSellerMultiSigPubKey(); + if (multiSigPubKey == null) + return null; + var multiSigPubKeyString = Utilities.bytesAsHexString(multiSigPubKey); + var multiSigAddress = btcWalletService.getAddressEntryListAsImmutableList().stream() + .filter(e -> e.getKeyPair().getPublicKeyAsHex().equals(multiSigPubKeyString)) + .findAny() + .orElse(null); + if (multiSigAddress == null) + return null; + + // Get payout address + var payoutAddress = isMyRoleBuyer ? + contract.getBuyerPayoutAddressString() : contract.getSellerPayoutAddressString(); + var payoutAddressEntry = btcWalletService.getAddressEntryListAsImmutableList().stream() + .filter(e -> Objects.equals(e.getAddressString(), payoutAddress)) + .findAny() + .orElse(null); + if (payoutAddressEntry == null) + return null; + + return new Tuple2<>(multiSigAddress.getAddressString(), payoutAddress); + } +} diff --git a/core/src/main/java/bisq/core/trade/failed/FailedTradesManager.java b/core/src/main/java/bisq/core/trade/failed/FailedTradesManager.java index ab771bb4bf2..44c5a3c6e34 100644 --- a/core/src/main/java/bisq/core/trade/failed/FailedTradesManager.java +++ b/core/src/main/java/bisq/core/trade/failed/FailedTradesManager.java @@ -17,12 +17,14 @@ package bisq.core.trade.failed; +import bisq.core.btc.model.AddressEntry; import bisq.core.btc.wallet.BtcWalletService; import bisq.core.offer.Offer; import bisq.core.provider.price.PriceFeedService; import bisq.core.trade.DumpDelayedPayoutTx; import bisq.core.trade.TradableList; import bisq.core.trade.Trade; +import bisq.core.trade.TradeUtils; import bisq.common.crypto.KeyRing; import bisq.common.proto.persistable.PersistedDataHost; @@ -33,7 +35,7 @@ import javafx.collections.ObservableList; import java.util.Optional; -import java.util.function.Consumer; +import java.util.function.Function; import java.util.stream.Stream; import org.slf4j.Logger; @@ -50,7 +52,7 @@ public class FailedTradesManager implements PersistedDataHost { private final Storage> tradableListStorage; private final DumpDelayedPayoutTx dumpDelayedPayoutTx; @Setter - private Consumer unfailTradeCallback; + private Function unfailTradeCallback; @Inject public FailedTradesManager(KeyRing keyRing, @@ -103,8 +105,29 @@ public Stream getTradesStreamWithFundsLockedIn() { } public void unfailTrade(Trade trade) { - if (unfailTradeCallback == null) return; - unfailTradeCallback.accept(trade); - failedTrades.remove(trade); + if (unfailTradeCallback == null) + return; + + if (unfailTradeCallback.apply(trade)) { + failedTrades.remove(trade); + } + } + + public String checkUnfail(Trade trade) { + var addresses = TradeUtils.getTradeAddresses(trade, btcWalletService, keyRing); + if (addresses == null) { + return "Addresses not found"; + } + StringBuilder blockingTrades = new StringBuilder(); + for (var entry : btcWalletService.getAddressEntryListAsImmutableList()) { + if (entry.getContext() == AddressEntry.Context.AVAILABLE) + continue; + if (entry.getAddressString() != null && + (entry.getAddressString().equals(addresses.first) || + entry.getAddressString().equals(addresses.second))) { + blockingTrades.append(entry.getOfferId()).append(", "); + } + } + return blockingTrades.toString(); } } diff --git a/core/src/main/resources/i18n/displayStrings.properties b/core/src/main/resources/i18n/displayStrings.properties index 66609c30e52..e483d0d712a 100644 --- a/core/src/main/resources/i18n/displayStrings.properties +++ b/core/src/main/resources/i18n/displayStrings.properties @@ -859,8 +859,11 @@ portfolio.closed.ticketClosed=Arbitrated portfolio.closed.mediationTicketClosed=Mediated portfolio.closed.canceled=Canceled portfolio.failed.Failed=Failed -portfolio.failed.unfail=Do you want to move this trade back to pending trades? \ - Only do this if you need to open a support ticket. +portfolio.failed.unfail=Before proceeding, make sure you have a backup of your data directory!\n\ + Do you want to move this trade back to open trades?\n\ + This is a way to unlock funds stuck in a failed trade. +portfolio.failed.cantUnfail=This trade cannot be moved back to open trades at the moment. \n\ + Try again after completion of trade(s) {0} #################################################################### diff --git a/desktop/src/main/java/bisq/desktop/main/portfolio/failedtrades/FailedTradesDataModel.java b/desktop/src/main/java/bisq/desktop/main/portfolio/failedtrades/FailedTradesDataModel.java index 048a643962e..2b7dd31f7e5 100644 --- a/desktop/src/main/java/bisq/desktop/main/portfolio/failedtrades/FailedTradesDataModel.java +++ b/desktop/src/main/java/bisq/desktop/main/portfolio/failedtrades/FailedTradesDataModel.java @@ -77,4 +77,8 @@ private void applyList() { public void unfailTrade(Trade trade) { failedTradesManager.unfailTrade(trade); } + + public String checkUnfail(Trade trade) { + return failedTradesManager.checkUnfail(trade); + } } diff --git a/desktop/src/main/java/bisq/desktop/main/portfolio/failedtrades/FailedTradesView.java b/desktop/src/main/java/bisq/desktop/main/portfolio/failedtrades/FailedTradesView.java index fd3f0121c82..c93f0d1cdaa 100644 --- a/desktop/src/main/java/bisq/desktop/main/portfolio/failedtrades/FailedTradesView.java +++ b/desktop/src/main/java/bisq/desktop/main/portfolio/failedtrades/FailedTradesView.java @@ -108,9 +108,16 @@ public void initialize() { keyEventEventHandler = keyEvent -> { if (Utilities.isAltOrCtrlPressed(KeyCode.Y, keyEvent)) { - new Popup().warning(Res.get("portfolio.failed.unfail")) - .onAction(this::onUnfail) - .show(); + var checkUnfailString = checkUnfail(); + if (!checkUnfailString.isEmpty()) { + new Popup().warning(Res.get("portfolio.failed.cantUnfail", checkUnfailString)) + .onAction(this::onUnfail) + .show(); + } else { + new Popup().warning(Res.get("portfolio.failed.unfail")) + .onAction(this::onUnfail) + .show(); + } } }; @@ -119,6 +126,11 @@ public void initialize() { private void onUnfail() { Trade trade = sortedList.get(tableView.getSelectionModel().getFocusedIndex()).getTrade(); model.dataModel.unfailTrade(trade); + } + + private String checkUnfail() { + Trade trade = sortedList.get(tableView.getSelectionModel().getFocusedIndex()).getTrade(); + return model.dataModel.checkUnfail(trade); } From 486f2547732e9923d070e59e6781da7fb8425d5e Mon Sep 17 00:00:00 2001 From: sqrrm Date: Fri, 10 Apr 2020 16:40:17 +0200 Subject: [PATCH 3/7] Don't unfail if deposit or delayedpayout txs are missing --- .../resources/i18n/displayStrings.properties | 2 ++ .../failedtrades/FailedTradesView.java | 17 +++++++++++++++-- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/core/src/main/resources/i18n/displayStrings.properties b/core/src/main/resources/i18n/displayStrings.properties index e483d0d712a..e6356622129 100644 --- a/core/src/main/resources/i18n/displayStrings.properties +++ b/core/src/main/resources/i18n/displayStrings.properties @@ -864,6 +864,8 @@ portfolio.failed.unfail=Before proceeding, make sure you have a backup of your d This is a way to unlock funds stuck in a failed trade. portfolio.failed.cantUnfail=This trade cannot be moved back to open trades at the moment. \n\ Try again after completion of trade(s) {0} +portfolio.failed.depositTxNull=The trade cannot be completed. Deposit transaction is null +portfolio.failed.delayedPayoutTxNull=The trade cannot be completed. Delayed payout transaction is null #################################################################### diff --git a/desktop/src/main/java/bisq/desktop/main/portfolio/failedtrades/FailedTradesView.java b/desktop/src/main/java/bisq/desktop/main/portfolio/failedtrades/FailedTradesView.java index c93f0d1cdaa..2da0632db8b 100644 --- a/desktop/src/main/java/bisq/desktop/main/portfolio/failedtrades/FailedTradesView.java +++ b/desktop/src/main/java/bisq/desktop/main/portfolio/failedtrades/FailedTradesView.java @@ -108,10 +108,13 @@ public void initialize() { keyEventEventHandler = keyEvent -> { if (Utilities.isAltOrCtrlPressed(KeyCode.Y, keyEvent)) { + var checkTxs = checkTxs(); var checkUnfailString = checkUnfail(); - if (!checkUnfailString.isEmpty()) { + if (!checkTxs.isEmpty()) { + new Popup().warning(checkTxs) + .show(); + } else if (!checkUnfailString.isEmpty()) { new Popup().warning(Res.get("portfolio.failed.cantUnfail", checkUnfailString)) - .onAction(this::onUnfail) .show(); } else { new Popup().warning(Res.get("portfolio.failed.unfail")) @@ -131,7 +134,17 @@ private void onUnfail() { private String checkUnfail() { Trade trade = sortedList.get(tableView.getSelectionModel().getFocusedIndex()).getTrade(); return model.dataModel.checkUnfail(trade); + } + private String checkTxs() { + Trade trade = sortedList.get(tableView.getSelectionModel().getFocusedIndex()).getTrade(); + if (trade.getDepositTx() == null) { + return Res.get("portfolio.failed.depositTxNull"); + } + if (trade.getDelayedPayoutTx() == null) { + return Res.get("portfolio.failed.delayedPayoutTxNull"); + } + return ""; } @Override From f6b7762d261e13a255776adb3daaa4a08fdd9b65 Mon Sep 17 00:00:00 2001 From: sqrrm Date: Sat, 11 Apr 2020 18:02:18 +0200 Subject: [PATCH 4/7] Init unfailed trade when moved to pending trades --- .../main/java/bisq/core/trade/TradeManager.java | 14 ++++++++++---- .../main/resources/i18n/displayStrings.properties | 2 ++ .../portfolio/failedtrades/FailedTradesView.java | 3 +-- .../pendingtrades/PendingTradesDataModel.java | 1 + .../pendingtrades/steps/TradeStepView.java | 9 +++++++-- 5 files changed, 21 insertions(+), 8 deletions(-) diff --git a/core/src/main/java/bisq/core/trade/TradeManager.java b/core/src/main/java/bisq/core/trade/TradeManager.java index 32eb8916cd0..2d0f61b76cb 100644 --- a/core/src/main/java/bisq/core/trade/TradeManager.java +++ b/core/src/main/java/bisq/core/trade/TradeManager.java @@ -283,10 +283,7 @@ private void initPendingTrades() { tradableList.forEach(trade -> { if (trade.isDepositPublished() || (trade.isTakerFeePublished() && !trade.hasFailed())) { - initTrade(trade, trade.getProcessModel().isUseSavingsWallet(), - trade.getProcessModel().getFundsNeededForTradeAsLong()); - trade.updateDepositTxFromWallet(); - tradesForStatistics.add(trade); + initPendingTrade(trade); } else if (trade.isTakerFeePublished() && !trade.isFundsLockedIn()) { addTradeToFailedTradesList.add(trade); trade.appendErrorMessage("Invalid state: trade.isTakerFeePublished() && !trade.isFundsLockedIn()"); @@ -340,6 +337,13 @@ private void initPendingTrades() { pendingTradesInitialized.set(true); } + private void initPendingTrade(Trade trade) { + initTrade(trade, trade.getProcessModel().isUseSavingsWallet(), + trade.getProcessModel().getFundsNeededForTradeAsLong()); + trade.updateDepositTxFromWallet(); + tradesForStatistics.add(trade); + } + private void onTradesChanged() { this.numPendingTrades.set(tradableList.getList().size()); } @@ -614,6 +618,8 @@ private boolean unfailTrade(Trade trade) { return false; } + initPendingTrade(trade); + if (!tradableList.contains(trade)) { tradableList.add(trade); } diff --git a/core/src/main/resources/i18n/displayStrings.properties b/core/src/main/resources/i18n/displayStrings.properties index e6356622129..0b0577d5c21 100644 --- a/core/src/main/resources/i18n/displayStrings.properties +++ b/core/src/main/resources/i18n/displayStrings.properties @@ -791,6 +791,8 @@ portfolio.pending.error.depositTxNull=The deposit transaction is null. You canno For further help please contact the Bisq support channel at the Bisq Keybase team. portfolio.pending.mediationResult.error.depositTxNull=The deposit transaction is null. The trade gets moved to the \ failed trades section. +portfolio.pending.mediationResult.error.delayedPayoutTxNull=The delayed payout transaction is null. The trade gets \ + moved to the failed trades section. portfolio.pending.error.depositTxNotConfirmed=The deposit transaction is not confirmed. You can not open an arbitration dispute \ with an unconfirmed deposit transaction. Please wait until it is confirmed or go to \"Settings/Network info\" and do a SPV resync.\n\n\ For further help please contact the Bisq support channel at the Bisq Keybase team. diff --git a/desktop/src/main/java/bisq/desktop/main/portfolio/failedtrades/FailedTradesView.java b/desktop/src/main/java/bisq/desktop/main/portfolio/failedtrades/FailedTradesView.java index 2da0632db8b..75679be01b8 100644 --- a/desktop/src/main/java/bisq/desktop/main/portfolio/failedtrades/FailedTradesView.java +++ b/desktop/src/main/java/bisq/desktop/main/portfolio/failedtrades/FailedTradesView.java @@ -123,7 +123,6 @@ public void initialize() { } } }; - } private void onUnfail() { @@ -141,7 +140,7 @@ private String checkTxs() { if (trade.getDepositTx() == null) { return Res.get("portfolio.failed.depositTxNull"); } - if (trade.getDelayedPayoutTx() == null) { + if (trade.getDelayedPayoutTxBytes() == null) { return Res.get("portfolio.failed.delayedPayoutTxNull"); } return ""; diff --git a/desktop/src/main/java/bisq/desktop/main/portfolio/pendingtrades/PendingTradesDataModel.java b/desktop/src/main/java/bisq/desktop/main/portfolio/pendingtrades/PendingTradesDataModel.java index 49d79a0874a..9f5276f9b97 100644 --- a/desktop/src/main/java/bisq/desktop/main/portfolio/pendingtrades/PendingTradesDataModel.java +++ b/desktop/src/main/java/bisq/desktop/main/portfolio/pendingtrades/PendingTradesDataModel.java @@ -591,6 +591,7 @@ private void doOpenDispute(boolean isSupportTicket, Transaction depositTx) { resultHandler = () -> navigation.navigateTo(MainView.class, SupportView.class, RefundClientView.class); if (trade.getDelayedPayoutTx() == null) { + log.error("Delayed payout tx is missing"); return; } diff --git a/desktop/src/main/java/bisq/desktop/main/portfolio/pendingtrades/steps/TradeStepView.java b/desktop/src/main/java/bisq/desktop/main/portfolio/pendingtrades/steps/TradeStepView.java index ef82e67448d..4945754fdb5 100644 --- a/desktop/src/main/java/bisq/desktop/main/portfolio/pendingtrades/steps/TradeStepView.java +++ b/desktop/src/main/java/bisq/desktop/main/portfolio/pendingtrades/steps/TradeStepView.java @@ -522,12 +522,17 @@ private void openMediationResultPopup(String headLine) { return; } - if (trade.getDepositTx() == null || trade.getDelayedPayoutTx() == null) { - log.error("trade.getDepositTx() or trade.getDelayedPayoutTx() was null at openMediationResultPopup. " + + if (trade.getDepositTx() == null) { + log.error("trade.getDepositTx() was null at openMediationResultPopup. " + "We add the trade to failed trades. TradeId={}", trade.getId()); model.dataModel.addTradeToFailedTrades(); new Popup().warning(Res.get("portfolio.pending.mediationResult.error.depositTxNull")).show(); return; + } else if (trade.getDelayedPayoutTx() == null) { + log.error("trade.getDelayedPayoutTx() was null at openMediationResultPopup. " + + "We add the trade to failed trades. TradeId={}", trade.getId()); + new Popup().warning(Res.get("portfolio.pending.mediationResult.error.delayedPayoutTxNull")).show(); + return; } DisputeResult disputeResult = optionalDispute.get().getDisputeResultProperty().get(); From be3158427e7fb26a0c564f9ff450b20991709862 Mon Sep 17 00:00:00 2001 From: sqrrm Date: Sun, 12 Apr 2020 13:03:09 +0200 Subject: [PATCH 5/7] Allow completion of trades with amount mismatch delayed tx --- .../bisq/core/trade/DelayedPayoutTxValidation.java | 10 ++++++++-- core/src/main/java/bisq/core/trade/TradeManager.java | 2 ++ .../tasks/buyer/BuyerVerifiesFinalDelayedPayoutTx.java | 3 ++- .../buyer/BuyerVerifiesPreparedDelayedPayoutTx.java | 3 ++- core/src/main/resources/i18n/displayStrings.properties | 5 ++--- .../pendingtrades/steps/buyer/BuyerStep1View.java | 7 ++++++- .../pendingtrades/steps/buyer/BuyerStep2View.java | 7 ++++++- 7 files changed, 28 insertions(+), 9 deletions(-) diff --git a/core/src/main/java/bisq/core/trade/DelayedPayoutTxValidation.java b/core/src/main/java/bisq/core/trade/DelayedPayoutTxValidation.java index aaaf026e19f..0db6e9e50f8 100644 --- a/core/src/main/java/bisq/core/trade/DelayedPayoutTxValidation.java +++ b/core/src/main/java/bisq/core/trade/DelayedPayoutTxValidation.java @@ -58,6 +58,12 @@ public static class InvalidTxException extends Exception { } } + public static class AmountMismatchException extends Exception { + AmountMismatchException(String msg) { + super(msg); + } + } + public static class InvalidLockTimeException extends Exception { InvalidLockTimeException(String msg) { super(msg); @@ -69,7 +75,7 @@ public static void validatePayoutTx(Trade trade, DaoFacade daoFacade, BtcWalletService btcWalletService) throws DonationAddressException, MissingDelayedPayoutTxException, - InvalidTxException, InvalidLockTimeException { + InvalidTxException, InvalidLockTimeException, AmountMismatchException { String errorMsg; if (delayedPayoutTx == null) { errorMsg = "DelayedPayoutTx must not be null"; @@ -122,7 +128,7 @@ public static void validatePayoutTx(Trade trade, errorMsg = "Output value of deposit tx and delayed payout tx is not matching. Output: " + output + " / msOutputAmount: " + msOutputAmount; log.error(errorMsg); log.error(delayedPayoutTx.toString()); - throw new InvalidTxException(errorMsg); + throw new AmountMismatchException(errorMsg); } diff --git a/core/src/main/java/bisq/core/trade/TradeManager.java b/core/src/main/java/bisq/core/trade/TradeManager.java index 2d0f61b76cb..875ee6c338b 100644 --- a/core/src/main/java/bisq/core/trade/TradeManager.java +++ b/core/src/main/java/bisq/core/trade/TradeManager.java @@ -312,6 +312,8 @@ private void initPendingTrades() { log.warn("We move the trade with ID '{}' to failed trades because of exception {}", trade.getId(), e.getMessage()); addTradeToFailedTradesList.add(trade); + } catch (DelayedPayoutTxValidation.AmountMismatchException e) { + log.warn("Delayed payout tx exception, trade {}, exception {}", trade.getId(), e.getMessage()); } } ); diff --git a/core/src/main/java/bisq/core/trade/protocol/tasks/buyer/BuyerVerifiesFinalDelayedPayoutTx.java b/core/src/main/java/bisq/core/trade/protocol/tasks/buyer/BuyerVerifiesFinalDelayedPayoutTx.java index d0ebb8a509b..468ec7dca81 100644 --- a/core/src/main/java/bisq/core/trade/protocol/tasks/buyer/BuyerVerifiesFinalDelayedPayoutTx.java +++ b/core/src/main/java/bisq/core/trade/protocol/tasks/buyer/BuyerVerifiesFinalDelayedPayoutTx.java @@ -50,7 +50,8 @@ protected void run() { } catch (DelayedPayoutTxValidation.DonationAddressException | DelayedPayoutTxValidation.MissingDelayedPayoutTxException | DelayedPayoutTxValidation.InvalidTxException | - DelayedPayoutTxValidation.InvalidLockTimeException e) { + DelayedPayoutTxValidation.InvalidLockTimeException | + DelayedPayoutTxValidation.AmountMismatchException e) { failed(e.getMessage()); } catch (Throwable t) { failed(t); diff --git a/core/src/main/java/bisq/core/trade/protocol/tasks/buyer/BuyerVerifiesPreparedDelayedPayoutTx.java b/core/src/main/java/bisq/core/trade/protocol/tasks/buyer/BuyerVerifiesPreparedDelayedPayoutTx.java index ea9c2a7cbf4..3242ba8cf6a 100644 --- a/core/src/main/java/bisq/core/trade/protocol/tasks/buyer/BuyerVerifiesPreparedDelayedPayoutTx.java +++ b/core/src/main/java/bisq/core/trade/protocol/tasks/buyer/BuyerVerifiesPreparedDelayedPayoutTx.java @@ -46,7 +46,8 @@ protected void run() { } catch (DelayedPayoutTxValidation.DonationAddressException | DelayedPayoutTxValidation.MissingDelayedPayoutTxException | DelayedPayoutTxValidation.InvalidTxException | - DelayedPayoutTxValidation.InvalidLockTimeException e) { + DelayedPayoutTxValidation.InvalidLockTimeException | + DelayedPayoutTxValidation.AmountMismatchException e) { failed(e.getMessage()); } catch (Throwable t) { failed(t); diff --git a/core/src/main/resources/i18n/displayStrings.properties b/core/src/main/resources/i18n/displayStrings.properties index 0b0577d5c21..1c2e7febef5 100644 --- a/core/src/main/resources/i18n/displayStrings.properties +++ b/core/src/main/resources/i18n/displayStrings.properties @@ -557,9 +557,8 @@ portfolio.tab.history=History portfolio.tab.failed=Failed portfolio.tab.editOpenOffer=Edit offer -portfolio.pending.invalidDelayedPayoutTx=The donation address in the delayed payout transaction is invalid.\n\n\ - Please do NOT send the Altcoin or Fiat payment but contact the Bisq developers at 'https://bisq.community' or \ - the Keybase channel.\n\n\ +portfolio.pending.invalidDelayedPayoutTx=Please do NOT send the Altcoin or Fiat payment but contact the Bisq \ + developers at 'https://bisq.community' or the Keybase channel.\n\n\ {0} portfolio.pending.step1.waitForConf=Wait for blockchain confirmation diff --git a/desktop/src/main/java/bisq/desktop/main/portfolio/pendingtrades/steps/buyer/BuyerStep1View.java b/desktop/src/main/java/bisq/desktop/main/portfolio/pendingtrades/steps/buyer/BuyerStep1View.java index 9c90991880b..2c42f3ef512 100644 --- a/desktop/src/main/java/bisq/desktop/main/portfolio/pendingtrades/steps/buyer/BuyerStep1View.java +++ b/desktop/src/main/java/bisq/desktop/main/portfolio/pendingtrades/steps/buyer/BuyerStep1View.java @@ -45,11 +45,16 @@ public void activate() { model.dataModel.btcWalletService); } catch (DelayedPayoutTxValidation.DonationAddressException | DelayedPayoutTxValidation.InvalidTxException | +// DelayedPayoutTxValidation.AmountMismatchException | // todo activate june 2020 DelayedPayoutTxValidation.InvalidLockTimeException e) { new Popup().warning(Res.get("portfolio.pending.invalidDelayedPayoutTx", e.getMessage())).show(); - } catch (DelayedPayoutTxValidation.MissingDelayedPayoutTxException ignore) { + } catch (DelayedPayoutTxValidation.MissingDelayedPayoutTxException | + DelayedPayoutTxValidation.AmountMismatchException ignore) { // We don't react on those errors as a failed trade might get listed initially but getting removed from the // trade manager after initPendingTrades which happens after activate might be called. + + // Allow amount mismatch until june 2020 to get trades through as it's due to a bug that has now been fixed. + // No new trades with mismatch can be created after v1.3.1 } } diff --git a/desktop/src/main/java/bisq/desktop/main/portfolio/pendingtrades/steps/buyer/BuyerStep2View.java b/desktop/src/main/java/bisq/desktop/main/portfolio/pendingtrades/steps/buyer/BuyerStep2View.java index fb212e170b2..d21d52fe505 100644 --- a/desktop/src/main/java/bisq/desktop/main/portfolio/pendingtrades/steps/buyer/BuyerStep2View.java +++ b/desktop/src/main/java/bisq/desktop/main/portfolio/pendingtrades/steps/buyer/BuyerStep2View.java @@ -122,11 +122,16 @@ public void activate() { model.dataModel.btcWalletService); } catch (DelayedPayoutTxValidation.DonationAddressException | DelayedPayoutTxValidation.InvalidTxException | +// DelayedPayoutTxValidation.AmountMismatchException | // todo activate june 2020 DelayedPayoutTxValidation.InvalidLockTimeException e) { new Popup().warning(Res.get("portfolio.pending.invalidDelayedPayoutTx", e.getMessage())).show(); - } catch (DelayedPayoutTxValidation.MissingDelayedPayoutTxException ignore) { + } catch (DelayedPayoutTxValidation.MissingDelayedPayoutTxException | + DelayedPayoutTxValidation.AmountMismatchException ignore) { // We don't react on those errors as a failed trade might get listed initially but getting removed from the // trade manager after initPendingTrades which happens after activate might be called. + + // Allow amount mismatch until june 2020 to get trades through as it's due to a bug that has now been fixed. + // No new trades with mismatch can be created after v1.3.1 } if (timeoutTimer != null) From 790db8c731992cdf0be1a8b5af68273ab2bf8ae0 Mon Sep 17 00:00:00 2001 From: sqrrm Date: Sun, 12 Apr 2020 16:12:43 +0200 Subject: [PATCH 6/7] Add option to allow faulty delay payout tx Add more logging during unfail process --- .../main/java/bisq/common/config/Config.java | 10 +++++++++ .../java/bisq/core/trade/TradeManager.java | 21 ++++++++++++------- .../java/bisq/core/trade/TradeModule.java | 2 ++ .../trade/failed/FailedTradesManager.java | 4 ++++ .../failedtrades/FailedTradesView.java | 17 +++++++++++++-- .../steps/buyer/BuyerStep1View.java | 12 +++++------ .../steps/buyer/BuyerStep2View.java | 12 +++++------ 7 files changed, 55 insertions(+), 23 deletions(-) diff --git a/common/src/main/java/bisq/common/config/Config.java b/common/src/main/java/bisq/common/config/Config.java index d7b0e0e4192..0d0173222c0 100644 --- a/common/src/main/java/bisq/common/config/Config.java +++ b/common/src/main/java/bisq/common/config/Config.java @@ -115,6 +115,7 @@ public class Config { public static final String GENESIS_TOTAL_SUPPLY = "genesisTotalSupply"; public static final String DAO_ACTIVATED = "daoActivated"; public static final String DUMP_DELAYED_PAYOUT_TXS = "dumpDelayedPayoutTxs"; + public static final String ALLOW_FAULTY_DELAYED_TXS = "allowFaultyDelayedTxs"; // Default values for certain options public static final int UNSPECIFIED_PORT = -1; @@ -197,6 +198,7 @@ public class Config { public final int genesisBlockHeight; public final long genesisTotalSupply; public final boolean dumpDelayedPayoutTxs; + public final boolean allowFaultyDelayedTxs; // Properties derived from options but not exposed as options themselves public final File torDir; @@ -606,6 +608,13 @@ public Config(String defaultAppName, File defaultUserDataDir, String... args) { .ofType(boolean.class) .defaultsTo(false); + ArgumentAcceptingOptionSpec allowFaultyDelayedTxsOpt = + parser.accepts(ALLOW_FAULTY_DELAYED_TXS, "Allow completion of trades with faulty delayed " + + "payout transactions") + .withRequiredArg() + .ofType(boolean.class) + .defaultsTo(true); + try { CompositeOptionSet options = new CompositeOptionSet(); @@ -717,6 +726,7 @@ public Config(String defaultAppName, File defaultUserDataDir, String... args) { this.genesisTotalSupply = options.valueOf(genesisTotalSupplyOpt); this.daoActivated = options.valueOf(daoActivatedOpt); this.dumpDelayedPayoutTxs = options.valueOf(dumpDelayedPayoutTxsOpt); + this.allowFaultyDelayedTxs = options.valueOf(allowFaultyDelayedTxsOpt); } catch (OptionException ex) { throw new ConfigException("problem parsing option '%s': %s", ex.options().get(0), diff --git a/core/src/main/java/bisq/core/trade/TradeManager.java b/core/src/main/java/bisq/core/trade/TradeManager.java index 875ee6c338b..e755789b312 100644 --- a/core/src/main/java/bisq/core/trade/TradeManager.java +++ b/core/src/main/java/bisq/core/trade/TradeManager.java @@ -57,6 +57,7 @@ import bisq.network.p2p.SendMailboxMessageListener; import bisq.common.ClockWatcher; +import bisq.common.config.Config; import bisq.common.crypto.KeyRing; import bisq.common.handlers.ErrorMessageHandler; import bisq.common.handlers.FaultHandler; @@ -74,6 +75,7 @@ import org.bitcoinj.core.TransactionConfidence; import javax.inject.Inject; +import javax.inject.Named; import com.google.common.util.concurrent.FutureCallback; @@ -145,6 +147,8 @@ public class TradeManager implements PersistedDataHost { @Getter private final ObservableList tradesWithoutDepositTx = FXCollections.observableArrayList(); private final DumpDelayedPayoutTx dumpDelayedPayoutTx; + @Getter + private final boolean allowFaultyDelayedTxs; /////////////////////////////////////////////////////////////////////////////////////////// @@ -172,7 +176,8 @@ public TradeManager(User user, DaoFacade daoFacade, ClockWatcher clockWatcher, Storage> storage, - DumpDelayedPayoutTx dumpDelayedPayoutTx) { + DumpDelayedPayoutTx dumpDelayedPayoutTx, + @Named(Config.ALLOW_FAULTY_DELAYED_TXS) boolean allowFaultyDelayedTxs) { this.user = user; this.keyRing = keyRing; this.btcWalletService = btcWalletService; @@ -193,6 +198,7 @@ public TradeManager(User user, this.daoFacade = daoFacade; this.clockWatcher = clockWatcher; this.dumpDelayedPayoutTx = dumpDelayedPayoutTx; + this.allowFaultyDelayedTxs = allowFaultyDelayedTxs; tradableListStorage = storage; @@ -307,13 +313,14 @@ private void initPendingTrades() { } catch (DelayedPayoutTxValidation.DonationAddressException | DelayedPayoutTxValidation.InvalidTxException | DelayedPayoutTxValidation.InvalidLockTimeException | - DelayedPayoutTxValidation.MissingDelayedPayoutTxException e) { - // We move it to failed trades so it cannot be continued. - log.warn("We move the trade with ID '{}' to failed trades because of exception {}", - trade.getId(), e.getMessage()); - addTradeToFailedTradesList.add(trade); - } catch (DelayedPayoutTxValidation.AmountMismatchException e) { + DelayedPayoutTxValidation.MissingDelayedPayoutTxException | + DelayedPayoutTxValidation.AmountMismatchException e) { log.warn("Delayed payout tx exception, trade {}, exception {}", trade.getId(), e.getMessage()); + if (!allowFaultyDelayedTxs) { + // We move it to failed trades so it cannot be continued. + log.warn("We move the trade with ID '{}' to failed trades", trade.getId()); + addTradeToFailedTradesList.add(trade); + } } } ); diff --git a/core/src/main/java/bisq/core/trade/TradeModule.java b/core/src/main/java/bisq/core/trade/TradeModule.java index b421b9d149b..bdf5ea78e1f 100644 --- a/core/src/main/java/bisq/core/trade/TradeModule.java +++ b/core/src/main/java/bisq/core/trade/TradeModule.java @@ -33,6 +33,7 @@ import com.google.inject.Singleton; +import static bisq.common.config.Config.ALLOW_FAULTY_DELAYED_TXS; import static bisq.common.config.Config.DUMP_DELAYED_PAYOUT_TXS; import static bisq.common.config.Config.DUMP_STATISTICS; import static com.google.inject.name.Names.named; @@ -58,5 +59,6 @@ protected void configure() { bind(AssetTradeActivityCheck.class).in(Singleton.class); bindConstant().annotatedWith(named(DUMP_STATISTICS)).to(config.dumpStatistics); bindConstant().annotatedWith(named(DUMP_DELAYED_PAYOUT_TXS)).to(config.dumpDelayedPayoutTxs); + bindConstant().annotatedWith(named(ALLOW_FAULTY_DELAYED_TXS)).to(config.allowFaultyDelayedTxs); } } diff --git a/core/src/main/java/bisq/core/trade/failed/FailedTradesManager.java b/core/src/main/java/bisq/core/trade/failed/FailedTradesManager.java index 44c5a3c6e34..ed7b633847e 100644 --- a/core/src/main/java/bisq/core/trade/failed/FailedTradesManager.java +++ b/core/src/main/java/bisq/core/trade/failed/FailedTradesManager.java @@ -26,12 +26,15 @@ import bisq.core.trade.Trade; import bisq.core.trade.TradeUtils; +import bisq.common.config.Config; import bisq.common.crypto.KeyRing; import bisq.common.proto.persistable.PersistedDataHost; import bisq.common.storage.Storage; import com.google.inject.Inject; +import javax.inject.Named; + import javafx.collections.ObservableList; import java.util.Optional; @@ -109,6 +112,7 @@ public void unfailTrade(Trade trade) { return; if (unfailTradeCallback.apply(trade)) { + log.info("Unfailing trade {}", trade.getId()); failedTrades.remove(trade); } } diff --git a/desktop/src/main/java/bisq/desktop/main/portfolio/failedtrades/FailedTradesView.java b/desktop/src/main/java/bisq/desktop/main/portfolio/failedtrades/FailedTradesView.java index 75679be01b8..2f22f370633 100644 --- a/desktop/src/main/java/bisq/desktop/main/portfolio/failedtrades/FailedTradesView.java +++ b/desktop/src/main/java/bisq/desktop/main/portfolio/failedtrades/FailedTradesView.java @@ -27,9 +27,11 @@ import bisq.core.locale.Res; import bisq.core.trade.Trade; +import bisq.common.config.Config; import bisq.common.util.Utilities; import javax.inject.Inject; +import javax.inject.Named; import javafx.fxml.FXML; @@ -64,11 +66,15 @@ public class FailedTradesView extends ActivatableViewAndModel sortedList; private EventHandler keyEventEventHandler; private Scene scene; + private final boolean allowFaultyDelayedTxs; @Inject - public FailedTradesView(FailedTradesViewModel model, TradeDetailsWindow tradeDetailsWindow) { + public FailedTradesView(FailedTradesViewModel model, + TradeDetailsWindow tradeDetailsWindow, + @Named(Config.ALLOW_FAULTY_DELAYED_TXS) boolean allowFaultyDelayedTxs) { super(model); this.tradeDetailsWindow = tradeDetailsWindow; + this.allowFaultyDelayedTxs = allowFaultyDelayedTxs; } @Override @@ -111,9 +117,11 @@ public void initialize() { var checkTxs = checkTxs(); var checkUnfailString = checkUnfail(); if (!checkTxs.isEmpty()) { + log.warn("Cannot unfail, error {}", checkTxs); new Popup().warning(checkTxs) .show(); } else if (!checkUnfailString.isEmpty()) { + log.warn("Cannot unfail, error {}", checkUnfailString); new Popup().warning(Res.get("portfolio.failed.cantUnfail", checkUnfailString)) .show(); } else { @@ -137,11 +145,16 @@ private String checkUnfail() { private String checkTxs() { Trade trade = sortedList.get(tableView.getSelectionModel().getFocusedIndex()).getTrade(); + log.info("Initiated unfail of trade {}", trade.getId()); if (trade.getDepositTx() == null) { + log.info("Check unfail found no depositTx for trade {}", trade.getId()); return Res.get("portfolio.failed.depositTxNull"); } if (trade.getDelayedPayoutTxBytes() == null) { - return Res.get("portfolio.failed.delayedPayoutTxNull"); + log.info("Check unfail found no delayedPayoutTxBytes for trade {}", trade.getId()); + if (!allowFaultyDelayedTxs) { + return Res.get("portfolio.failed.delayedPayoutTxNull"); + } } return ""; } diff --git a/desktop/src/main/java/bisq/desktop/main/portfolio/pendingtrades/steps/buyer/BuyerStep1View.java b/desktop/src/main/java/bisq/desktop/main/portfolio/pendingtrades/steps/buyer/BuyerStep1View.java index 2c42f3ef512..184dcd038f9 100644 --- a/desktop/src/main/java/bisq/desktop/main/portfolio/pendingtrades/steps/buyer/BuyerStep1View.java +++ b/desktop/src/main/java/bisq/desktop/main/portfolio/pendingtrades/steps/buyer/BuyerStep1View.java @@ -45,16 +45,14 @@ public void activate() { model.dataModel.btcWalletService); } catch (DelayedPayoutTxValidation.DonationAddressException | DelayedPayoutTxValidation.InvalidTxException | -// DelayedPayoutTxValidation.AmountMismatchException | // todo activate june 2020 + DelayedPayoutTxValidation.AmountMismatchException | DelayedPayoutTxValidation.InvalidLockTimeException e) { - new Popup().warning(Res.get("portfolio.pending.invalidDelayedPayoutTx", e.getMessage())).show(); - } catch (DelayedPayoutTxValidation.MissingDelayedPayoutTxException | - DelayedPayoutTxValidation.AmountMismatchException ignore) { + if (!model.dataModel.tradeManager.isAllowFaultyDelayedTxs()) { + new Popup().warning(Res.get("portfolio.pending.invalidDelayedPayoutTx", e.getMessage())).show(); + } + } catch (DelayedPayoutTxValidation.MissingDelayedPayoutTxException ignore) { // We don't react on those errors as a failed trade might get listed initially but getting removed from the // trade manager after initPendingTrades which happens after activate might be called. - - // Allow amount mismatch until june 2020 to get trades through as it's due to a bug that has now been fixed. - // No new trades with mismatch can be created after v1.3.1 } } diff --git a/desktop/src/main/java/bisq/desktop/main/portfolio/pendingtrades/steps/buyer/BuyerStep2View.java b/desktop/src/main/java/bisq/desktop/main/portfolio/pendingtrades/steps/buyer/BuyerStep2View.java index d21d52fe505..80826ccbde4 100644 --- a/desktop/src/main/java/bisq/desktop/main/portfolio/pendingtrades/steps/buyer/BuyerStep2View.java +++ b/desktop/src/main/java/bisq/desktop/main/portfolio/pendingtrades/steps/buyer/BuyerStep2View.java @@ -122,16 +122,14 @@ public void activate() { model.dataModel.btcWalletService); } catch (DelayedPayoutTxValidation.DonationAddressException | DelayedPayoutTxValidation.InvalidTxException | -// DelayedPayoutTxValidation.AmountMismatchException | // todo activate june 2020 + DelayedPayoutTxValidation.AmountMismatchException | DelayedPayoutTxValidation.InvalidLockTimeException e) { - new Popup().warning(Res.get("portfolio.pending.invalidDelayedPayoutTx", e.getMessage())).show(); - } catch (DelayedPayoutTxValidation.MissingDelayedPayoutTxException | - DelayedPayoutTxValidation.AmountMismatchException ignore) { + if (!model.dataModel.tradeManager.isAllowFaultyDelayedTxs()) { + new Popup().warning(Res.get("portfolio.pending.invalidDelayedPayoutTx", e.getMessage())).show(); + } + } catch (DelayedPayoutTxValidation.MissingDelayedPayoutTxException ignore) { // We don't react on those errors as a failed trade might get listed initially but getting removed from the // trade manager after initPendingTrades which happens after activate might be called. - - // Allow amount mismatch until june 2020 to get trades through as it's due to a bug that has now been fixed. - // No new trades with mismatch can be created after v1.3.1 } if (timeoutTimer != null) From 2bd00c8c019f673895f9ff8f86d2e455ca29e680 Mon Sep 17 00:00:00 2001 From: sqrrm Date: Sun, 12 Apr 2020 16:17:23 +0200 Subject: [PATCH 7/7] Change command line argument default --- common/src/main/java/bisq/common/config/Config.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/src/main/java/bisq/common/config/Config.java b/common/src/main/java/bisq/common/config/Config.java index 0d0173222c0..b959d4ec1c4 100644 --- a/common/src/main/java/bisq/common/config/Config.java +++ b/common/src/main/java/bisq/common/config/Config.java @@ -613,7 +613,7 @@ public Config(String defaultAppName, File defaultUserDataDir, String... args) { "payout transactions") .withRequiredArg() .ofType(boolean.class) - .defaultsTo(true); + .defaultsTo(false); try { CompositeOptionSet options = new CompositeOptionSet();