mirror of
https://github.com/haveno-dex/haveno.git
synced 2024-12-22 11:39:29 +00:00
fix invalid signature when sign offer re-requested after timeout
This commit is contained in:
parent
e12ec197bf
commit
88290c9dff
5 changed files with 63 additions and 50 deletions
|
@ -230,9 +230,12 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
|
|||
offerBookService.addOfferBookChangedListener(new OfferBookChangedListener() {
|
||||
@Override
|
||||
public void onAdded(Offer offer) {
|
||||
|
||||
// cancel offer if reserved funds spent
|
||||
Optional<OpenOffer> openOfferOptional = getOpenOfferById(offer.getId());
|
||||
if (openOfferOptional.isPresent() && openOfferOptional.get().getState() != OpenOffer.State.RESERVED && offer.isReservedFundsSpent()) {
|
||||
closeOpenOffer(offer);
|
||||
log.warn("Canceling open offer because reserved funds have been spent, offerId={}, state={}", offer.getId(), openOfferOptional.get().getState());
|
||||
cancelOpenOffer(openOfferOptional.get(), null, null);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
|
@ -552,7 +555,7 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
|
|||
if (openOffer.isCanceled()) latch.countDown();
|
||||
else {
|
||||
log.warn("Error processing unposted offer {}: {}", openOffer.getId(), errorMessage);
|
||||
doCancel(openOffer);
|
||||
doCancelOffer(openOffer);
|
||||
offer.setErrorMessage(errorMessage);
|
||||
latch.countDown();
|
||||
errorMessageHandler.handleErrorMessage(errorMessage);
|
||||
|
@ -622,19 +625,19 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
|
|||
offerBookService.removeOffer(openOffer.getOffer().getOfferPayload(),
|
||||
() -> {
|
||||
ThreadUtils.submitToPool(() -> { // TODO: this runs off thread and then shows popup when done. should show overlay spinner until done
|
||||
doCancel(openOffer);
|
||||
resultHandler.handleResult();
|
||||
doCancelOffer(openOffer);
|
||||
if (resultHandler != null) resultHandler.handleResult();
|
||||
});
|
||||
},
|
||||
errorMessageHandler);
|
||||
} else {
|
||||
ThreadUtils.submitToPool(() -> {
|
||||
doCancel(openOffer);
|
||||
resultHandler.handleResult();
|
||||
doCancelOffer(openOffer);
|
||||
if (resultHandler != null) resultHandler.handleResult();
|
||||
});
|
||||
}
|
||||
} else {
|
||||
errorMessageHandler.handleErrorMessage("You can't remove an offer that is currently edited.");
|
||||
if (errorMessageHandler != null) errorMessageHandler.handleErrorMessage("You can't remove an offer that is currently edited.");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -708,7 +711,7 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
|
|||
}
|
||||
|
||||
// remove open offer which thaws its key images
|
||||
private void doCancel(@NotNull OpenOffer openOffer) {
|
||||
private void doCancelOffer(@NotNull OpenOffer openOffer) {
|
||||
Offer offer = openOffer.getOffer();
|
||||
offer.setState(Offer.State.REMOVED);
|
||||
openOffer.setState(OpenOffer.State.CANCELED);
|
||||
|
@ -874,7 +877,7 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
|
|||
if (scheduledOffer.getNumProcessingAttempts() >= MAX_PROCESS_ATTEMPTS) {
|
||||
log.warn("Offer canceled after {} attempts, offerId={}, error={}", scheduledOffer.getNumProcessingAttempts(), scheduledOffer.getId(), errorMessage);
|
||||
HavenoUtils.havenoSetup.getTopErrorMsg().set("Offer canceled after " + scheduledOffer.getNumProcessingAttempts() + " attempts. Please switch to a better Monero connection and try again.\n\nOffer ID: " + scheduledOffer.getId() + "\nError: " + errorMessage);
|
||||
doCancel(scheduledOffer);
|
||||
doCancelOffer(scheduledOffer);
|
||||
}
|
||||
errorMessages.add(errorMessage);
|
||||
}
|
||||
|
@ -1754,7 +1757,7 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
|
|||
} else {
|
||||
|
||||
// cancel and recreate offer
|
||||
doCancel(openOffer);
|
||||
doCancelOffer(openOffer);
|
||||
Offer updatedOffer = new Offer(openOffer.getOffer().getOfferPayload());
|
||||
updatedOffer.setPriceFeedService(priceFeedService);
|
||||
OpenOffer updatedOpenOffer = new OpenOffer(updatedOffer, openOffer.getTriggerPrice());
|
||||
|
@ -1770,7 +1773,7 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
|
|||
}, (errorMessage) -> {
|
||||
if (!updatedOpenOffer.isCanceled()) {
|
||||
log.warn("Error reposting offer {}: {}", updatedOpenOffer.getId(), errorMessage);
|
||||
doCancel(updatedOpenOffer);
|
||||
doCancelOffer(updatedOpenOffer);
|
||||
updatedOffer.setErrorMessage(errorMessage);
|
||||
}
|
||||
latch.countDown();
|
||||
|
|
|
@ -91,47 +91,54 @@ public class PlaceOfferProtocol {
|
|||
|
||||
// TODO (woodser): switch to fluent
|
||||
public void handleSignOfferResponse(SignOfferResponse response, NodeAddress sender) {
|
||||
log.debug("handleSignOfferResponse() " + model.getOpenOffer().getOffer().getId());
|
||||
model.setSignOfferResponse(response);
|
||||
log.debug("handleSignOfferResponse() " + model.getOpenOffer().getOffer().getId());
|
||||
model.setSignOfferResponse(response);
|
||||
|
||||
if (!model.getOpenOffer().getOffer().getOfferPayload().getArbitratorSigner().equals(sender)) {
|
||||
log.warn("Ignoring sign offer response from different sender");
|
||||
return;
|
||||
}
|
||||
// ignore if unexpected signer
|
||||
if (!model.getOpenOffer().getOffer().getOfferPayload().getArbitratorSigner().equals(sender)) {
|
||||
log.warn("Ignoring sign offer response from different sender");
|
||||
return;
|
||||
}
|
||||
|
||||
// ignore if timer already stopped
|
||||
if (timeoutTimer == null) {
|
||||
log.warn("Ignoring sign offer response from arbitrator because timeout has expired for offer " + model.getOpenOffer().getOffer().getId());
|
||||
return;
|
||||
}
|
||||
// ignore if payloads have different timestamps
|
||||
if (model.getOpenOffer().getOffer().getOfferPayload().getDate() != response.getSignedOfferPayload().getDate()) {
|
||||
log.warn("Ignoring sign offer response from arbitrator for offer payload with different timestamp");
|
||||
return;
|
||||
}
|
||||
|
||||
// reset timer
|
||||
startTimeoutTimer();
|
||||
// ignore if timer already stopped
|
||||
if (timeoutTimer == null) {
|
||||
log.warn("Ignoring sign offer response from arbitrator because timeout has expired for offer " + model.getOpenOffer().getOffer().getId());
|
||||
return;
|
||||
}
|
||||
|
||||
TaskRunner<PlaceOfferModel> taskRunner = new TaskRunner<>(model,
|
||||
() -> {
|
||||
log.debug("sequence at handleSignOfferResponse completed");
|
||||
stopTimeoutTimer();
|
||||
resultHandler.handleResult(model.getTransaction()); // TODO (woodser): XMR transaction instead
|
||||
},
|
||||
(errorMessage) -> {
|
||||
if (model.isOfferAddedToOfferBook()) {
|
||||
model.getOfferBookService().removeOffer(model.getOpenOffer().getOffer().getOfferPayload(),
|
||||
() -> {
|
||||
model.setOfferAddedToOfferBook(false);
|
||||
log.debug("OfferPayload removed from offer book.");
|
||||
},
|
||||
log::error);
|
||||
}
|
||||
handleError(errorMessage);
|
||||
}
|
||||
);
|
||||
taskRunner.addTasks(
|
||||
MakerProcessSignOfferResponse.class,
|
||||
AddToOfferBook.class
|
||||
);
|
||||
// reset timer
|
||||
startTimeoutTimer();
|
||||
|
||||
taskRunner.run();
|
||||
TaskRunner<PlaceOfferModel> taskRunner = new TaskRunner<>(model,
|
||||
() -> {
|
||||
log.debug("sequence at handleSignOfferResponse completed");
|
||||
stopTimeoutTimer();
|
||||
resultHandler.handleResult(model.getTransaction()); // TODO (woodser): XMR transaction instead
|
||||
},
|
||||
(errorMessage) -> {
|
||||
if (model.isOfferAddedToOfferBook()) {
|
||||
model.getOfferBookService().removeOffer(model.getOpenOffer().getOffer().getOfferPayload(),
|
||||
() -> {
|
||||
model.setOfferAddedToOfferBook(false);
|
||||
log.debug("OfferPayload removed from offer book.");
|
||||
},
|
||||
log::error);
|
||||
}
|
||||
handleError(errorMessage);
|
||||
}
|
||||
);
|
||||
taskRunner.addTasks(
|
||||
MakerProcessSignOfferResponse.class,
|
||||
AddToOfferBook.class
|
||||
);
|
||||
|
||||
taskRunner.run();
|
||||
}
|
||||
|
||||
public void startTimeoutTimer() {
|
||||
|
|
|
@ -42,11 +42,14 @@ public class MakerProcessSignOfferResponse extends Task<PlaceOfferModel> {
|
|||
|
||||
// validate arbitrator signature
|
||||
if (!HavenoUtils.isArbitratorSignatureValid(model.getSignOfferResponse().getSignedOfferPayload(), arbitrator)) {
|
||||
throw new RuntimeException("Offer payload has invalid arbitrator signature");
|
||||
throw new RuntimeException("Arbitrator's offer payload has invalid signature, offerId=" + offer.getId());
|
||||
}
|
||||
|
||||
// set arbitrator signature for maker's offer
|
||||
offer.getOfferPayload().setArbitratorSignature(model.getSignOfferResponse().getSignedOfferPayload().getArbitratorSignature());
|
||||
if (!HavenoUtils.isArbitratorSignatureValid(offer.getOfferPayload(), arbitrator)) {
|
||||
throw new RuntimeException("Maker's offer payload has invalid signature, offerId=" + offer.getId());
|
||||
}
|
||||
offer.setState(Offer.State.AVAILABLE);
|
||||
complete();
|
||||
} catch (Exception e) {
|
||||
|
|
|
@ -364,7 +364,7 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi
|
|||
trade.onShutDownStarted();
|
||||
} catch (Exception e) {
|
||||
if (e.getMessage() != null && e.getMessage().contains("Connection reset")) return; // expected if shut down with ctrl+c
|
||||
log.warn("Error notifying {} {} that shut down started {}", getClass().getSimpleName(), trade.getId());
|
||||
log.warn("Error notifying {} {} that shut down started {}", trade.getClass().getSimpleName(), trade.getId());
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
|
|
|
@ -221,7 +221,7 @@ public class ArbitratorProcessDepositRequest extends TradeTask {
|
|||
processModel.getP2PService().sendEncryptedDirectMessage(nodeAddress, pubKeyRing, response, new SendDirectMessageListener() {
|
||||
@Override
|
||||
public void onArrived() {
|
||||
log.info("{} arrived: trading peer={}; offerId={}; uid={}", response.getClass().getSimpleName(), nodeAddress, trade.getId());
|
||||
log.info("{} arrived: trading peer={}; offerId={}; uid={}", response.getClass().getSimpleName(), nodeAddress, trade.getId(), trade.getUid());
|
||||
}
|
||||
@Override
|
||||
public void onFault(String errorMessage) {
|
||||
|
|
Loading…
Reference in a new issue