handle timeout during place offer protocol

This commit is contained in:
woodser 2022-07-15 15:52:06 -04:00
parent e726071841
commit 83b8616f6f
3 changed files with 53 additions and 55 deletions

View file

@ -17,6 +17,7 @@
package bisq.core.offer.placeoffer; package bisq.core.offer.placeoffer;
import bisq.core.locale.Res;
import bisq.core.offer.messages.SignOfferResponse; import bisq.core.offer.messages.SignOfferResponse;
import bisq.core.offer.placeoffer.tasks.AddToOfferBook; import bisq.core.offer.placeoffer.tasks.AddToOfferBook;
import bisq.core.offer.placeoffer.tasks.MakerReservesOfferFunds; import bisq.core.offer.placeoffer.tasks.MakerReservesOfferFunds;
@ -24,7 +25,10 @@ import bisq.core.offer.placeoffer.tasks.MakerSendsSignOfferRequest;
import bisq.core.offer.placeoffer.tasks.MakerProcessesSignOfferResponse; import bisq.core.offer.placeoffer.tasks.MakerProcessesSignOfferResponse;
import bisq.core.offer.placeoffer.tasks.ValidateOffer; import bisq.core.offer.placeoffer.tasks.ValidateOffer;
import bisq.core.trade.handlers.TransactionResultHandler; import bisq.core.trade.handlers.TransactionResultHandler;
import bisq.core.trade.protocol.TradeProtocol;
import bisq.network.p2p.NodeAddress; import bisq.network.p2p.NodeAddress;
import bisq.common.Timer;
import bisq.common.UserThread;
import bisq.common.handlers.ErrorMessageHandler; import bisq.common.handlers.ErrorMessageHandler;
import bisq.common.taskrunner.TaskRunner; import bisq.common.taskrunner.TaskRunner;
@ -35,6 +39,7 @@ public class PlaceOfferProtocol {
private static final Logger log = LoggerFactory.getLogger(PlaceOfferProtocol.class); private static final Logger log = LoggerFactory.getLogger(PlaceOfferProtocol.class);
private final PlaceOfferModel model; private final PlaceOfferModel model;
private Timer timeoutTimer;
private final TransactionResultHandler resultHandler; private final TransactionResultHandler resultHandler;
private final ErrorMessageHandler errorMessageHandler; private final ErrorMessageHandler errorMessageHandler;
@ -58,14 +63,16 @@ public class PlaceOfferProtocol {
public void placeOffer() { public void placeOffer() {
log.debug("placeOffer() " + model.getOffer().getId()); log.debug("placeOffer() " + model.getOffer().getId());
timeoutTimer = UserThread.runAfter(() -> {
handleError(Res.get("createOffer.timeoutAtPublishing"));
}, TradeProtocol.TRADE_TIMEOUT);
TaskRunner<PlaceOfferModel> taskRunner = new TaskRunner<>(model, TaskRunner<PlaceOfferModel> taskRunner = new TaskRunner<>(model,
() -> { () -> {
log.debug("sequence at placeOffer completed");
}, },
(errorMessage) -> { (errorMessage) -> {
log.error(errorMessage); handleError(errorMessage);
model.getOffer().setErrorMessage(errorMessage);
errorMessageHandler.handleErrorMessage(errorMessage);
} }
); );
taskRunner.addTasks( taskRunner.addTasks(
@ -81,19 +88,29 @@ public class PlaceOfferProtocol {
public void handleSignOfferResponse(SignOfferResponse response, NodeAddress sender) { public void handleSignOfferResponse(SignOfferResponse response, NodeAddress sender) {
log.debug("handleSignOfferResponse() " + model.getOffer().getId()); log.debug("handleSignOfferResponse() " + model.getOffer().getId());
model.setSignOfferResponse(response); model.setSignOfferResponse(response);
if (!model.getOffer().getOfferPayload().getArbitratorSigner().equals(sender)) { if (!model.getOffer().getOfferPayload().getArbitratorSigner().equals(sender)) {
log.warn("Ignoring sign offer response from different sender"); log.warn("Ignoring sign offer response from different sender");
return; return;
} }
// ignore if timer already stopped
if (timeoutTimer == null) {
log.warn("Ignoring sign offer response from arbitrator because timeout has expired");
return;
}
timeoutTimer = UserThread.runAfter(() -> {
handleError(Res.get("createOffer.timeoutAtPublishing"));
}, TradeProtocol.TRADE_TIMEOUT);
TaskRunner<PlaceOfferModel> taskRunner = new TaskRunner<>(model, TaskRunner<PlaceOfferModel> taskRunner = new TaskRunner<>(model,
() -> { () -> {
log.debug("sequence at handleSignOfferResponse completed"); log.debug("sequence at handleSignOfferResponse completed");
stopTimeoutTimer();
resultHandler.handleResult(model.getTransaction()); // TODO (woodser): XMR transaction instead resultHandler.handleResult(model.getTransaction()); // TODO (woodser): XMR transaction instead
}, },
(errorMessage) -> { (errorMessage) -> {
log.error(errorMessage);
if (model.isOfferAddedToOfferBook()) { if (model.isOfferAddedToOfferBook()) {
model.getOfferBookService().removeOffer(model.getOffer().getOfferPayload(), model.getOfferBookService().removeOffer(model.getOffer().getOfferPayload(),
() -> { () -> {
@ -102,8 +119,7 @@ public class PlaceOfferProtocol {
}, },
log::error); log::error);
} }
model.getOffer().setErrorMessage(errorMessage); handleError(errorMessage);
errorMessageHandler.handleErrorMessage(errorMessage);
} }
); );
taskRunner.addTasks( taskRunner.addTasks(
@ -113,4 +129,20 @@ public class PlaceOfferProtocol {
taskRunner.run(); taskRunner.run();
} }
private void stopTimeoutTimer() {
if (timeoutTimer != null) {
timeoutTimer.stop();
timeoutTimer = null;
}
}
private void handleError(String errorMessage) {
if (timeoutTimer != null) {
log.error(errorMessage);
stopTimeoutTimer();
model.getOffer().setErrorMessage(errorMessage);
errorMessageHandler.handleErrorMessage(errorMessage);
}
}
} }

View file

@ -50,7 +50,7 @@ import bisq.core.util.coin.CoinFormatter;
import bisq.core.util.coin.CoinUtil; import bisq.core.util.coin.CoinUtil;
import bisq.network.p2p.P2PService; import bisq.network.p2p.P2PService;
import bisq.common.handlers.ErrorMessageHandler;
import bisq.common.util.MathUtils; import bisq.common.util.MathUtils;
import bisq.common.util.Utilities; import bisq.common.util.Utilities;
@ -90,8 +90,6 @@ import java.util.stream.Collectors;
import lombok.Getter; import lombok.Getter;
import javax.annotation.Nullable;
import static bisq.core.payment.payload.PaymentMethod.HAL_CASH_ID; import static bisq.core.payment.payload.PaymentMethod.HAL_CASH_ID;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import static java.util.Comparator.comparing; import static java.util.Comparator.comparing;
@ -313,12 +311,12 @@ public abstract class MutableOfferDataModel extends OfferDataModel {
paymentAccount); paymentAccount);
} }
void onPlaceOffer(Offer offer, TransactionResultHandler resultHandler) { void onPlaceOffer(Offer offer, TransactionResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) {
openOfferManager.placeOffer(offer, openOfferManager.placeOffer(offer,
useSavingsWallet, useSavingsWallet,
triggerPrice, triggerPrice,
resultHandler, resultHandler,
log::error); errorMessageHandler);
} }
void onPaymentAccountSelected(PaymentAccount paymentAccount) { void onPaymentAccountSelected(PaymentAccount paymentAccount) {

View file

@ -58,7 +58,6 @@ import bisq.core.util.validation.AltcoinValidator;
import bisq.core.util.validation.FiatPriceValidator; import bisq.core.util.validation.FiatPriceValidator;
import bisq.core.util.validation.InputValidator; import bisq.core.util.validation.InputValidator;
import bisq.core.util.validation.MonetaryValidator; import bisq.core.util.validation.MonetaryValidator;
import bisq.common.Timer;
import bisq.common.UserThread; import bisq.common.UserThread;
import bisq.common.app.DevEnv; import bisq.common.app.DevEnv;
import bisq.common.util.MathUtils; import bisq.common.util.MathUtils;
@ -173,7 +172,6 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
private ChangeListener<Boolean> isWalletFundedListener; private ChangeListener<Boolean> isWalletFundedListener;
private ChangeListener<String> errorMessageListener; private ChangeListener<String> errorMessageListener;
protected Offer offer; protected Offer offer;
private Timer timeoutTimer;
private boolean inputIsMarketBasedPrice; private boolean inputIsMarketBasedPrice;
private ChangeListener<Boolean> useMarketBasedPriceListener; private ChangeListener<Boolean> useMarketBasedPriceListener;
private boolean ignorePriceStringListener, ignoreVolumeStringListener, ignoreAmountStringListener, ignoreSecurityDepositStringListener; private boolean ignorePriceStringListener, ignoreVolumeStringListener, ignoreAmountStringListener, ignoreSecurityDepositStringListener;
@ -253,7 +251,6 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
protected void deactivate() { protected void deactivate() {
removeBindings(); removeBindings();
removeListeners(); removeListeners();
stopTimeoutTimer();
} }
private void addBindings() { private void addBindings() {
@ -611,41 +608,19 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
errorMessage.set(null); errorMessage.set(null);
createOfferRequested = true; createOfferRequested = true;
if (timeoutTimer == null) {
timeoutTimer = UserThread.runAfter(() -> {
stopTimeoutTimer();
createOfferRequested = false;
errorMessage.set(Res.get("createOffer.timeoutAtPublishing"));
updateButtonDisableState();
updateSpinnerInfo();
resultHandler.run();
}, 60);
}
errorMessageListener = (observable, oldValue, newValue) -> {
if (newValue != null) {
stopTimeoutTimer();
createOfferRequested = false;
if (offer.getState() == Offer.State.OFFER_FEE_RESERVED)
errorMessage.set(newValue + Res.get("createOffer.errorInfo"));
else
errorMessage.set(newValue);
updateButtonDisableState();
updateSpinnerInfo();
resultHandler.run();
}
};
offer.errorMessageProperty().addListener(errorMessageListener);
dataModel.onPlaceOffer(offer, transaction -> { dataModel.onPlaceOffer(offer, transaction -> {
stopTimeoutTimer();
resultHandler.run(); resultHandler.run();
placeOfferCompleted.set(true); placeOfferCompleted.set(true);
errorMessage.set(null); errorMessage.set(null);
}, errMessage -> {
createOfferRequested = false;
if (offer.getState() == Offer.State.OFFER_FEE_RESERVED) errorMessage.set(errMessage + Res.get("createOffer.errorInfo"));
else errorMessage.set(errMessage);
updateButtonDisableState();
updateSpinnerInfo();
resultHandler.run();
}); });
updateButtonDisableState(); updateButtonDisableState();
@ -1287,13 +1262,6 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
isPlaceOfferButtonDisabled.set(createOfferRequested || !inputDataValid || !dataModel.getIsBtcWalletFunded().get()); isPlaceOfferButtonDisabled.set(createOfferRequested || !inputDataValid || !dataModel.getIsBtcWalletFunded().get());
} }
private void stopTimeoutTimer() {
if (timeoutTimer != null) {
timeoutTimer.stop();
timeoutTimer = null;
}
}
private CoinFormatter getFormatterForMakerFee() { private CoinFormatter getFormatterForMakerFee() {
return btcFormatter; return btcFormatter;
} }