diff --git a/core/src/main/java/haveno/core/offer/OpenOfferManager.java b/core/src/main/java/haveno/core/offer/OpenOfferManager.java index 987158bfbe..997ab1a52e 100644 --- a/core/src/main/java/haveno/core/offer/OpenOfferManager.java +++ b/core/src/main/java/haveno/core/offer/OpenOfferManager.java @@ -1101,11 +1101,6 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe PlaceOfferProtocol placeOfferProtocol = new PlaceOfferProtocol(model, transaction -> { - // set reserve tx on open offer - openOffer.setReserveTxHash(model.getReserveTx().getHash()); - openOffer.setReserveTxHex(model.getReserveTx().getFullHex()); - openOffer.setReserveTxKey(model.getReserveTx().getKey()); - // set offer state openOffer.setState(OpenOffer.State.AVAILABLE); openOffer.setScheduledTxHashes(null); @@ -1609,9 +1604,19 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe private void republishOffer(OpenOffer openOffer, @Nullable Runnable completeHandler) { - // re-add to offer book if signature is valid + // determine if offer is valid + boolean isValid = true; Arbitrator arbitrator = user.getAcceptedArbitratorByAddress(openOffer.getOffer().getOfferPayload().getArbitratorSigner()); - boolean isValid = arbitrator != null && HavenoUtils.isArbitratorSignatureValid(openOffer.getOffer().getOfferPayload(), arbitrator); + if (arbitrator == null || !HavenoUtils.isArbitratorSignatureValid(openOffer.getOffer().getOfferPayload(), arbitrator)) { + log.warn("Offer {} has invalid arbitrator signature, reposting", openOffer.getId()); + isValid = false; + } + if (openOffer.getOffer().getOfferPayload().getReserveTxKeyImages() != null && (openOffer.getReserveTxHash() == null || openOffer.getReserveTxHash().isEmpty())) { + log.warn("Offer {} is missing reserve tx hash but has reserved key images, reposting", openOffer.getId()); + isValid = false; + } + + // if valid, re-add offer to book if (isValid) { offerBookService.addOffer(openOffer.getOffer(), () -> { @@ -1635,35 +1640,34 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe if (completeHandler != null) completeHandler.run(); } }); - return; + } else { + + // cancel and recreate offer + onCancelled(openOffer); + Offer updatedOffer = new Offer(openOffer.getOffer().getOfferPayload()); + updatedOffer.setPriceFeedService(priceFeedService); + OpenOffer updatedOpenOffer = new OpenOffer(updatedOffer, openOffer.getTriggerPrice()); + + // repost offer + new Thread(() -> { + synchronized (processOffersLock) { + CountDownLatch latch = new CountDownLatch(1); + processUnpostedOffer(getOpenOffers(), updatedOpenOffer, (transaction) -> { + addOpenOffer(updatedOpenOffer); + requestPersistence(); + latch.countDown(); + if (completeHandler != null) completeHandler.run(); + }, (errorMessage) -> { + log.warn("Error reposting offer {}: {}", updatedOpenOffer.getId(), errorMessage); + onCancelled(updatedOpenOffer); + updatedOffer.setErrorMessage(errorMessage); + latch.countDown(); + if (completeHandler != null) completeHandler.run(); + }); + HavenoUtils.awaitLatch(latch); + } + }).start(); } - - // cancel and recreate offer - log.warn("Offer {} has invalid arbitrator signature, reposting", openOffer.getId()); - onCancelled(openOffer); - Offer updatedOffer = new Offer(openOffer.getOffer().getOfferPayload()); - updatedOffer.setPriceFeedService(priceFeedService); - OpenOffer updatedOpenOffer = new OpenOffer(updatedOffer, openOffer.getTriggerPrice()); - - // repost offer - new Thread(() -> { - synchronized (processOffersLock) { - CountDownLatch latch = new CountDownLatch(1); - processUnpostedOffer(getOpenOffers(), updatedOpenOffer, (transaction) -> { - addOpenOffer(updatedOpenOffer); - requestPersistence(); - latch.countDown(); - if (completeHandler != null) completeHandler.run(); - }, (errorMessage) -> { - log.warn("Error reposting offer {} with invalid signature: {}", updatedOpenOffer.getId(), errorMessage); - onCancelled(updatedOpenOffer); - updatedOffer.setErrorMessage(errorMessage); - latch.countDown(); - if (completeHandler != null) completeHandler.run(); - }); - HavenoUtils.awaitLatch(latch); - } - }).start(); } private void startPeriodicRepublishOffersTimer() { diff --git a/core/src/main/java/haveno/core/offer/placeoffer/tasks/MakerReserveOfferFunds.java b/core/src/main/java/haveno/core/offer/placeoffer/tasks/MakerReserveOfferFunds.java index 51887920aa..73bc8f9cb1 100644 --- a/core/src/main/java/haveno/core/offer/placeoffer/tasks/MakerReserveOfferFunds.java +++ b/core/src/main/java/haveno/core/offer/placeoffer/tasks/MakerReserveOfferFunds.java @@ -70,6 +70,9 @@ public class MakerReserveOfferFunds extends Task { // save offer state model.setReserveTx(reserveTx); + model.getOpenOffer().setReserveTxHash(reserveTx.getHash()); + model.getOpenOffer().setReserveTxHex(reserveTx.getFullHex()); + model.getOpenOffer().setReserveTxKey(reserveTx.getKey()); offer.getOfferPayload().setReserveTxKeyImages(reservedKeyImages); complete(); } catch (Throwable t) { diff --git a/core/src/main/java/haveno/core/trade/protocol/tasks/MakerSendInitTradeRequest.java b/core/src/main/java/haveno/core/trade/protocol/tasks/MakerSendInitTradeRequest.java index a257d55070..6ff740cc16 100644 --- a/core/src/main/java/haveno/core/trade/protocol/tasks/MakerSendInitTradeRequest.java +++ b/core/src/main/java/haveno/core/trade/protocol/tasks/MakerSendInitTradeRequest.java @@ -43,10 +43,11 @@ public class MakerSendInitTradeRequest extends TradeTask { try { runInterceptHook(); - // verify trade + // verify trade state InitTradeRequest makerRequest = (InitTradeRequest) processModel.getTradeMessage(); // arbitrator's InitTradeRequest to maker checkNotNull(makerRequest); checkTradeId(processModel.getOfferId(), makerRequest); + if (trade.getSelf().getReserveTxHash() == null || trade.getSelf().getReserveTxHash().isEmpty()) throw new IllegalStateException("Reserve tx id is not initialized: " + trade.getSelf().getReserveTxHash()); // create request to arbitrator Offer offer = processModel.getOffer();