mirror of
https://github.com/haveno-dex/haveno.git
synced 2024-11-17 08:17:57 +00:00
handle timeout during place offer protocol
This commit is contained in:
parent
e726071841
commit
83b8616f6f
3 changed files with 53 additions and 55 deletions
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue