mirror of
https://github.com/boldsuck/haveno.git
synced 2024-12-22 20:19:21 +00:00
preserve offers unless invalid #1115
This commit is contained in:
parent
06b0c20bad
commit
d69dcae875
6 changed files with 90 additions and 75 deletions
|
@ -53,7 +53,7 @@ import java.util.Optional;
|
||||||
public final class OpenOffer implements Tradable {
|
public final class OpenOffer implements Tradable {
|
||||||
|
|
||||||
public enum State {
|
public enum State {
|
||||||
SCHEDULED,
|
PENDING,
|
||||||
AVAILABLE,
|
AVAILABLE,
|
||||||
RESERVED,
|
RESERVED,
|
||||||
CLOSED,
|
CLOSED,
|
||||||
|
@ -120,7 +120,7 @@ public final class OpenOffer implements Tradable {
|
||||||
this.offer = offer;
|
this.offer = offer;
|
||||||
this.triggerPrice = triggerPrice;
|
this.triggerPrice = triggerPrice;
|
||||||
this.reserveExactAmount = reserveExactAmount;
|
this.reserveExactAmount = reserveExactAmount;
|
||||||
state = State.SCHEDULED;
|
state = State.PENDING;
|
||||||
}
|
}
|
||||||
|
|
||||||
public OpenOffer(Offer offer, long triggerPrice, OpenOffer openOffer) {
|
public OpenOffer(Offer offer, long triggerPrice, OpenOffer openOffer) {
|
||||||
|
@ -165,8 +165,8 @@ public final class OpenOffer implements Tradable {
|
||||||
this.reserveTxHex = reserveTxHex;
|
this.reserveTxHex = reserveTxHex;
|
||||||
this.reserveTxKey = reserveTxKey;
|
this.reserveTxKey = reserveTxKey;
|
||||||
|
|
||||||
if (this.state == State.RESERVED)
|
// reset reserved state to available
|
||||||
setState(State.AVAILABLE);
|
if (this.state == State.RESERVED) setState(State.AVAILABLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -232,8 +232,8 @@ public final class OpenOffer implements Tradable {
|
||||||
return stateProperty;
|
return stateProperty;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isScheduled() {
|
public boolean isPending() {
|
||||||
return state == State.SCHEDULED;
|
return state == State.PENDING;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isAvailable() {
|
public boolean isAvailable() {
|
||||||
|
|
|
@ -132,7 +132,7 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
|
||||||
private static final long REPUBLISH_AGAIN_AT_STARTUP_DELAY_SEC = 30;
|
private static final long REPUBLISH_AGAIN_AT_STARTUP_DELAY_SEC = 30;
|
||||||
private static final long REPUBLISH_INTERVAL_MS = TimeUnit.MINUTES.toMillis(30);
|
private static final long REPUBLISH_INTERVAL_MS = TimeUnit.MINUTES.toMillis(30);
|
||||||
private static final long REFRESH_INTERVAL_MS = OfferPayload.TTL / 2;
|
private static final long REFRESH_INTERVAL_MS = OfferPayload.TTL / 2;
|
||||||
private static final int MAX_PROCESS_ATTEMPTS = 5;
|
private static final int NUM_ATTEMPTS_THRESHOLD = 5; // process pending offer only on republish cycle after this many attempts
|
||||||
|
|
||||||
private final CoreContext coreContext;
|
private final CoreContext coreContext;
|
||||||
private final KeyRing keyRing;
|
private final KeyRing keyRing;
|
||||||
|
@ -252,17 +252,17 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
|
||||||
|
|
||||||
// read open offers
|
// read open offers
|
||||||
persistenceManager.readPersisted(persisted -> {
|
persistenceManager.readPersisted(persisted -> {
|
||||||
openOffers.setAll(persisted.getList());
|
openOffers.setAll(persisted.getList());
|
||||||
openOffers.forEach(openOffer -> openOffer.getOffer().setPriceFeedService(priceFeedService));
|
openOffers.forEach(openOffer -> openOffer.getOffer().setPriceFeedService(priceFeedService));
|
||||||
|
|
||||||
// read signed offers
|
// read signed offers
|
||||||
signedOfferPersistenceManager.readPersisted(signedOfferPersisted -> {
|
signedOfferPersistenceManager.readPersisted(signedOfferPersisted -> {
|
||||||
signedOffers.setAll(signedOfferPersisted.getList());
|
signedOffers.setAll(signedOfferPersisted.getList());
|
||||||
completeHandler.run();
|
completeHandler.run();
|
||||||
},
|
},
|
||||||
completeHandler);
|
completeHandler);
|
||||||
},
|
},
|
||||||
completeHandler);
|
completeHandler);
|
||||||
}
|
}
|
||||||
|
|
||||||
private synchronized void maybeInitializeKeyImagePoller() {
|
private synchronized void maybeInitializeKeyImagePoller() {
|
||||||
|
@ -472,17 +472,17 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
|
||||||
// .forEach(openOffer -> OfferUtil.getInvalidMakerFeeTxErrorMessage(openOffer.getOffer(), btcWalletService)
|
// .forEach(openOffer -> OfferUtil.getInvalidMakerFeeTxErrorMessage(openOffer.getOffer(), btcWalletService)
|
||||||
// .ifPresent(errorMsg -> invalidOffers.add(new Tuple2<>(openOffer, errorMsg))));
|
// .ifPresent(errorMsg -> invalidOffers.add(new Tuple2<>(openOffer, errorMsg))));
|
||||||
|
|
||||||
// process scheduled offers
|
// process pending offers
|
||||||
processScheduledOffers((transaction) -> {}, (errorMessage) -> {
|
processPendingOffers(false);
|
||||||
log.warn("Error processing unposted offers: " + errorMessage);
|
|
||||||
});
|
|
||||||
|
|
||||||
// register to process unposted offers on new block
|
// register to process pending offers on new block
|
||||||
xmrWalletService.addWalletListener(new MoneroWalletListener() {
|
xmrWalletService.addWalletListener(new MoneroWalletListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onNewBlock(long height) {
|
public void onNewBlock(long height) {
|
||||||
processScheduledOffers((transaction) -> {}, (errorMessage) -> {
|
|
||||||
log.warn("Error processing unposted offers on new block {}: {}", height, errorMessage);
|
// process pending offers on new block a few times
|
||||||
|
processPendingOffers(true, (transaction) -> {}, (errorMessage) -> {
|
||||||
|
log.warn("Error processing pending offers on new block {}: {}", height, errorMessage);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -549,16 +549,15 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
|
||||||
synchronized (processOffersLock) {
|
synchronized (processOffersLock) {
|
||||||
CountDownLatch latch = new CountDownLatch(1);
|
CountDownLatch latch = new CountDownLatch(1);
|
||||||
addOpenOffer(openOffer);
|
addOpenOffer(openOffer);
|
||||||
processUnpostedOffer(getOpenOffers(), openOffer, (transaction) -> {
|
processPendingOffer(getOpenOffers(), openOffer, (transaction) -> {
|
||||||
requestPersistence();
|
requestPersistence();
|
||||||
latch.countDown();
|
latch.countDown();
|
||||||
resultHandler.handleResult(transaction);
|
resultHandler.handleResult(transaction);
|
||||||
}, (errorMessage) -> {
|
}, (errorMessage) -> {
|
||||||
if (openOffer.isCanceled()) latch.countDown();
|
if (openOffer.isCanceled()) latch.countDown();
|
||||||
else {
|
else {
|
||||||
log.warn("Error processing unposted offer {}: {}", openOffer.getId(), errorMessage);
|
log.warn("Error processing pending offer {}: {}", openOffer.getId(), errorMessage);
|
||||||
doCancelOffer(openOffer);
|
doCancelOffer(openOffer);
|
||||||
offer.setErrorMessage(errorMessage);
|
|
||||||
latch.countDown();
|
latch.countDown();
|
||||||
errorMessageHandler.handleErrorMessage(errorMessage);
|
errorMessageHandler.handleErrorMessage(errorMessage);
|
||||||
}
|
}
|
||||||
|
@ -583,9 +582,11 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
|
||||||
public void activateOpenOffer(OpenOffer openOffer,
|
public void activateOpenOffer(OpenOffer openOffer,
|
||||||
ResultHandler resultHandler,
|
ResultHandler resultHandler,
|
||||||
ErrorMessageHandler errorMessageHandler) {
|
ErrorMessageHandler errorMessageHandler) {
|
||||||
if (openOffer.isScheduled()) {
|
if (openOffer.isPending()) {
|
||||||
resultHandler.handleResult(); // ignore if scheduled
|
resultHandler.handleResult(); // ignore if pending
|
||||||
} else if (!offersToBeEdited.containsKey(openOffer.getId())) {
|
} else if (offersToBeEdited.containsKey(openOffer.getId())) {
|
||||||
|
errorMessageHandler.handleErrorMessage("You can't activate an offer that is currently edited.");
|
||||||
|
} else {
|
||||||
Offer offer = openOffer.getOffer();
|
Offer offer = openOffer.getOffer();
|
||||||
offerBookService.activateOffer(offer,
|
offerBookService.activateOffer(offer,
|
||||||
() -> {
|
() -> {
|
||||||
|
@ -595,8 +596,6 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
|
||||||
resultHandler.handleResult();
|
resultHandler.handleResult();
|
||||||
},
|
},
|
||||||
errorMessageHandler);
|
errorMessageHandler);
|
||||||
} else {
|
|
||||||
errorMessageHandler.handleErrorMessage("You can't activate an offer that is currently edited.");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -858,26 +857,35 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
|
||||||
// Place offer helpers
|
// Place offer helpers
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
private void processScheduledOffers(TransactionResultHandler resultHandler, // TODO (woodser): transaction not needed with result handler
|
private void processPendingOffers(boolean skipOffersWithTooManyAttempts) {
|
||||||
|
processPendingOffers(skipOffersWithTooManyAttempts, (transaction) -> {}, (errorMessage) -> {
|
||||||
|
log.warn("Error processing pending offers: " + errorMessage);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void processPendingOffers(boolean skipOffersWithTooManyAttempts,
|
||||||
|
TransactionResultHandler resultHandler, // TODO (woodser): transaction not needed with result handler
|
||||||
ErrorMessageHandler errorMessageHandler) {
|
ErrorMessageHandler errorMessageHandler) {
|
||||||
ThreadUtils.execute(() -> {
|
ThreadUtils.execute(() -> {
|
||||||
synchronized (processOffersLock) {
|
synchronized (processOffersLock) {
|
||||||
List<String> errorMessages = new ArrayList<String>();
|
List<String> errorMessages = new ArrayList<String>();
|
||||||
List<OpenOffer> openOffers = getOpenOffers();
|
List<OpenOffer> openOffers = getOpenOffers();
|
||||||
for (OpenOffer scheduledOffer : openOffers) {
|
for (OpenOffer pendingOffer : openOffers) {
|
||||||
if (scheduledOffer.getState() != OpenOffer.State.SCHEDULED) continue;
|
if (pendingOffer.getState() != OpenOffer.State.PENDING) continue;
|
||||||
|
if (skipOffersWithTooManyAttempts && pendingOffer.getNumProcessingAttempts() > NUM_ATTEMPTS_THRESHOLD) continue; // skip offers with too many attempts
|
||||||
CountDownLatch latch = new CountDownLatch(1);
|
CountDownLatch latch = new CountDownLatch(1);
|
||||||
processUnpostedOffer(openOffers, scheduledOffer, (transaction) -> {
|
processPendingOffer(openOffers, pendingOffer, (transaction) -> {
|
||||||
latch.countDown();
|
latch.countDown();
|
||||||
}, errorMessage -> {
|
}, errorMessage -> {
|
||||||
if (!scheduledOffer.isCanceled()) {
|
if (!pendingOffer.isCanceled()) {
|
||||||
log.warn("Error processing unposted offer, offerId={}, attempt={}/{}, error={}", scheduledOffer.getId(), scheduledOffer.getNumProcessingAttempts(), MAX_PROCESS_ATTEMPTS, errorMessage);
|
log.warn("Error processing pending offer, offerId={}, attempt={}, error={}", pendingOffer.getId(), pendingOffer.getNumProcessingAttempts(), errorMessage);
|
||||||
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);
|
|
||||||
doCancelOffer(scheduledOffer);
|
|
||||||
}
|
|
||||||
errorMessages.add(errorMessage);
|
errorMessages.add(errorMessage);
|
||||||
|
|
||||||
|
// cancel offer if invalid
|
||||||
|
if (pendingOffer.getOffer().getState() == Offer.State.INVALID) {
|
||||||
|
log.warn("Canceling offer because it's invalid: {}", pendingOffer.getId());
|
||||||
|
doCancelOffer(pendingOffer);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
latch.countDown();
|
latch.countDown();
|
||||||
});
|
});
|
||||||
|
@ -890,7 +898,7 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
|
||||||
}, THREAD_ID);
|
}, THREAD_ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void processUnpostedOffer(List<OpenOffer> openOffers, OpenOffer openOffer, TransactionResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) {
|
private void processPendingOffer(List<OpenOffer> openOffers, OpenOffer openOffer, TransactionResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) {
|
||||||
|
|
||||||
// skip if already processing
|
// skip if already processing
|
||||||
if (openOffer.isProcessing()) {
|
if (openOffer.isProcessing()) {
|
||||||
|
@ -900,17 +908,18 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
|
||||||
|
|
||||||
// process offer
|
// process offer
|
||||||
openOffer.setProcessing(true);
|
openOffer.setProcessing(true);
|
||||||
doProcessUnpostedOffer(openOffers, openOffer, (transaction) -> {
|
doProcessPendingOffer(openOffers, openOffer, (transaction) -> {
|
||||||
openOffer.setProcessing(false);
|
openOffer.setProcessing(false);
|
||||||
resultHandler.handleResult(transaction);
|
resultHandler.handleResult(transaction);
|
||||||
}, (errorMsg) -> {
|
}, (errorMsg) -> {
|
||||||
openOffer.setProcessing(false);
|
openOffer.setProcessing(false);
|
||||||
openOffer.setNumProcessingAttempts(openOffer.getNumProcessingAttempts() + 1);
|
openOffer.setNumProcessingAttempts(openOffer.getNumProcessingAttempts() + 1);
|
||||||
|
openOffer.getOffer().setErrorMessage(errorMsg);
|
||||||
errorMessageHandler.handleErrorMessage(errorMsg);
|
errorMessageHandler.handleErrorMessage(errorMsg);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void doProcessUnpostedOffer(List<OpenOffer> openOffers, OpenOffer openOffer, TransactionResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) {
|
private void doProcessPendingOffer(List<OpenOffer> openOffers, OpenOffer openOffer, TransactionResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) {
|
||||||
new Thread(() -> {
|
new Thread(() -> {
|
||||||
try {
|
try {
|
||||||
|
|
||||||
|
@ -1075,7 +1084,7 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
|
||||||
openOffer.setSplitOutputTxFee(splitOutputTx.getFee().longValueExact());
|
openOffer.setSplitOutputTxFee(splitOutputTx.getFee().longValueExact());
|
||||||
openOffer.setScheduledTxHashes(Arrays.asList(splitOutputTx.getHash()));
|
openOffer.setScheduledTxHashes(Arrays.asList(splitOutputTx.getHash()));
|
||||||
openOffer.setScheduledAmount(openOffer.getOffer().getAmountNeeded().toString());
|
openOffer.setScheduledAmount(openOffer.getOffer().getAmountNeeded().toString());
|
||||||
openOffer.setState(OpenOffer.State.SCHEDULED);
|
openOffer.setState(OpenOffer.State.PENDING);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void scheduleWithEarliestTxs(List<OpenOffer> openOffers, OpenOffer openOffer) {
|
private void scheduleWithEarliestTxs(List<OpenOffer> openOffers, OpenOffer openOffer) {
|
||||||
|
@ -1106,13 +1115,13 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
|
||||||
// schedule txs
|
// schedule txs
|
||||||
openOffer.setScheduledTxHashes(scheduledTxHashes);
|
openOffer.setScheduledTxHashes(scheduledTxHashes);
|
||||||
openOffer.setScheduledAmount(scheduledAmount.toString());
|
openOffer.setScheduledAmount(scheduledAmount.toString());
|
||||||
openOffer.setState(OpenOffer.State.SCHEDULED);
|
openOffer.setState(OpenOffer.State.PENDING);
|
||||||
}
|
}
|
||||||
|
|
||||||
private BigInteger getScheduledAmount(List<OpenOffer> openOffers) {
|
private BigInteger getScheduledAmount(List<OpenOffer> openOffers) {
|
||||||
BigInteger scheduledAmount = BigInteger.ZERO;
|
BigInteger scheduledAmount = BigInteger.ZERO;
|
||||||
for (OpenOffer openOffer : openOffers) {
|
for (OpenOffer openOffer : openOffers) {
|
||||||
if (openOffer.getState() != OpenOffer.State.SCHEDULED) continue;
|
if (openOffer.getState() != OpenOffer.State.PENDING) continue;
|
||||||
if (openOffer.getScheduledTxHashes() == null) continue;
|
if (openOffer.getScheduledTxHashes() == null) continue;
|
||||||
List<MoneroTxWallet> fundingTxs = xmrWalletService.getTxs(openOffer.getScheduledTxHashes());
|
List<MoneroTxWallet> fundingTxs = xmrWalletService.getTxs(openOffer.getScheduledTxHashes());
|
||||||
for (MoneroTxWallet fundingTx : fundingTxs) {
|
for (MoneroTxWallet fundingTx : fundingTxs) {
|
||||||
|
@ -1129,7 +1138,7 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
|
||||||
private boolean isTxScheduledByOtherOffer(List<OpenOffer> openOffers, OpenOffer openOffer, String txHash) {
|
private boolean isTxScheduledByOtherOffer(List<OpenOffer> openOffers, OpenOffer openOffer, String txHash) {
|
||||||
for (OpenOffer otherOffer : openOffers) {
|
for (OpenOffer otherOffer : openOffers) {
|
||||||
if (otherOffer == openOffer) continue;
|
if (otherOffer == openOffer) continue;
|
||||||
if (otherOffer.getState() != OpenOffer.State.SCHEDULED) continue;
|
if (otherOffer.getState() != OpenOffer.State.PENDING) continue;
|
||||||
if (otherOffer.getScheduledTxHashes() == null) continue;
|
if (otherOffer.getScheduledTxHashes() == null) continue;
|
||||||
for (String scheduledTxHash : otherOffer.getScheduledTxHashes()) {
|
for (String scheduledTxHash : otherOffer.getScheduledTxHashes()) {
|
||||||
if (txHash.equals(scheduledTxHash)) return true;
|
if (txHash.equals(scheduledTxHash)) return true;
|
||||||
|
@ -1732,25 +1741,29 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
// cancel and recreate offer
|
// reset offer state to pending
|
||||||
doCancelOffer(openOffer);
|
openOffer.getOffer().getOfferPayload().setArbitratorSignature(null);
|
||||||
Offer updatedOffer = new Offer(openOffer.getOffer().getOfferPayload());
|
openOffer.getOffer().getOfferPayload().setArbitratorSigner(null);
|
||||||
updatedOffer.setPriceFeedService(priceFeedService);
|
openOffer.getOffer().setState(Offer.State.UNKNOWN);
|
||||||
OpenOffer updatedOpenOffer = new OpenOffer(updatedOffer, openOffer.getTriggerPrice());
|
openOffer.setState(OpenOffer.State.PENDING);
|
||||||
|
|
||||||
// repost offer
|
// republish offer
|
||||||
synchronized (processOffersLock) {
|
synchronized (processOffersLock) {
|
||||||
CountDownLatch latch = new CountDownLatch(1);
|
CountDownLatch latch = new CountDownLatch(1);
|
||||||
addOpenOffer(updatedOpenOffer);
|
processPendingOffer(getOpenOffers(), openOffer, (transaction) -> {
|
||||||
processUnpostedOffer(getOpenOffers(), updatedOpenOffer, (transaction) -> {
|
|
||||||
requestPersistence();
|
requestPersistence();
|
||||||
latch.countDown();
|
latch.countDown();
|
||||||
if (completeHandler != null) completeHandler.run();
|
if (completeHandler != null) completeHandler.run();
|
||||||
}, (errorMessage) -> {
|
}, (errorMessage) -> {
|
||||||
if (!updatedOpenOffer.isCanceled()) {
|
if (!openOffer.isCanceled()) {
|
||||||
log.warn("Error reposting offer {}: {}", updatedOpenOffer.getId(), errorMessage);
|
log.warn("Error republishing offer {}: {}", openOffer.getId(), errorMessage);
|
||||||
doCancelOffer(updatedOpenOffer);
|
openOffer.getOffer().setErrorMessage(errorMessage);
|
||||||
updatedOffer.setErrorMessage(errorMessage);
|
|
||||||
|
// cancel offer if invalid
|
||||||
|
if (openOffer.getOffer().getState() == Offer.State.INVALID) {
|
||||||
|
log.warn("Canceling offer because it's invalid: {}", openOffer.getId());
|
||||||
|
doCancelOffer(openOffer);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
latch.countDown();
|
latch.countDown();
|
||||||
if (completeHandler != null) completeHandler.run();
|
if (completeHandler != null) completeHandler.run();
|
||||||
|
|
|
@ -66,7 +66,7 @@ public class MakerReserveOfferFunds extends Task<PlaceOfferModel> {
|
||||||
synchronized (XmrWalletService.WALLET_LOCK) {
|
synchronized (XmrWalletService.WALLET_LOCK) {
|
||||||
|
|
||||||
// reset protocol timeout
|
// reset protocol timeout
|
||||||
verifyScheduled();
|
verifyPending();
|
||||||
model.getProtocol().startTimeoutTimer();
|
model.getProtocol().startTimeoutTimer();
|
||||||
|
|
||||||
// collect relevant info
|
// collect relevant info
|
||||||
|
@ -94,7 +94,7 @@ public class MakerReserveOfferFunds extends Task<PlaceOfferModel> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// verify still open
|
// verify still open
|
||||||
verifyScheduled();
|
verifyPending();
|
||||||
if (reserveTx != null) break;
|
if (reserveTx != null) break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -104,6 +104,7 @@ public class MakerReserveOfferFunds extends Task<PlaceOfferModel> {
|
||||||
model.getXmrWalletService().resetAddressEntriesForOpenOffer(offer.getId());
|
model.getXmrWalletService().resetAddressEntriesForOpenOffer(offer.getId());
|
||||||
if (reserveTx != null) {
|
if (reserveTx != null) {
|
||||||
model.getXmrWalletService().thawOutputs(HavenoUtils.getInputKeyImages(reserveTx));
|
model.getXmrWalletService().thawOutputs(HavenoUtils.getInputKeyImages(reserveTx));
|
||||||
|
offer.getOfferPayload().setReserveTxKeyImages(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
throw e;
|
throw e;
|
||||||
|
@ -131,7 +132,7 @@ public class MakerReserveOfferFunds extends Task<PlaceOfferModel> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void verifyScheduled() {
|
public void verifyPending() {
|
||||||
if (!model.getOpenOffer().isScheduled()) throw new RuntimeException("Offer " + model.getOpenOffer().getOffer().getId() + " is canceled");
|
if (!model.getOpenOffer().isPending()) throw new RuntimeException("Offer " + model.getOpenOffer().getOffer().getId() + " is canceled");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -116,9 +116,10 @@ public class MakerSendSignOfferRequest extends Task<PlaceOfferModel> {
|
||||||
model.getOpenOffer().getOffer().getOfferPayload().setArbitratorSigner(arbitratorNodeAddress);
|
model.getOpenOffer().getOffer().getOfferPayload().setArbitratorSigner(arbitratorNodeAddress);
|
||||||
model.getOpenOffer().getOffer().setState(Offer.State.OFFER_FEE_RESERVED);
|
model.getOpenOffer().getOffer().setState(Offer.State.OFFER_FEE_RESERVED);
|
||||||
resultHandler.handleResult();
|
resultHandler.handleResult();
|
||||||
} else {
|
} else {
|
||||||
errorMessageHandler.handleErrorMessage("Arbitrator nacked SignOfferRequest for offer " + request.getOfferId() + ": " + ackMessage.getErrorMessage());
|
model.getOpenOffer().getOffer().setState(Offer.State.INVALID);
|
||||||
}
|
errorMessageHandler.handleErrorMessage("Arbitrator nacked SignOfferRequest for offer " + request.getOfferId() + ": " + ackMessage.getErrorMessage());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
model.getP2PService().addDecryptedDirectMessageListener(ackListener);
|
model.getP2PService().addDecryptedDirectMessageListener(ackListener);
|
||||||
|
@ -137,9 +138,9 @@ public class MakerSendSignOfferRequest extends Task<PlaceOfferModel> {
|
||||||
log.warn("Arbitrator unavailable: address={}, error={}", arbitratorNodeAddress, errorMessage);
|
log.warn("Arbitrator unavailable: address={}, error={}", arbitratorNodeAddress, errorMessage);
|
||||||
excludedArbitrators.add(arbitratorNodeAddress);
|
excludedArbitrators.add(arbitratorNodeAddress);
|
||||||
|
|
||||||
// check if offer still scheduled
|
// check if offer still pending
|
||||||
if (!model.getOpenOffer().isScheduled()) {
|
if (!model.getOpenOffer().isPending()) {
|
||||||
errorMessageHandler.handleErrorMessage("Offer is no longer scheduled, offerId=" + model.getOpenOffer().getId());
|
errorMessageHandler.handleErrorMessage("Offer is no longer pending, offerId=" + model.getOpenOffer().getId());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -296,7 +296,7 @@ public class OpenOffersView extends ActivatableViewAndModel<VBox, OpenOffersView
|
||||||
|
|
||||||
private void updateSelectToggleButtonState() {
|
private void updateSelectToggleButtonState() {
|
||||||
List<OpenOfferListItem> availableItems = sortedList.stream()
|
List<OpenOfferListItem> availableItems = sortedList.stream()
|
||||||
.filter(openOfferListItem -> !openOfferListItem.getOpenOffer().isScheduled())
|
.filter(openOfferListItem -> !openOfferListItem.getOpenOffer().isPending())
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
if (availableItems.size() == 0) {
|
if (availableItems.size() == 0) {
|
||||||
selectToggleButton.setDisable(true);
|
selectToggleButton.setDisable(true);
|
||||||
|
@ -710,7 +710,7 @@ public class OpenOffersView extends ActivatableViewAndModel<VBox, OpenOffersView
|
||||||
offerStateChangeListeners.put(openOffer.getId(), listener);
|
offerStateChangeListeners.put(openOffer.getId(), listener);
|
||||||
openOffer.stateProperty().addListener(listener);
|
openOffer.stateProperty().addListener(listener);
|
||||||
|
|
||||||
if (openOffer.getState() == OpenOffer.State.SCHEDULED) {
|
if (openOffer.getState() == OpenOffer.State.PENDING) {
|
||||||
setGraphic(new AutoTooltipLabel(Res.get("shared.pending")));
|
setGraphic(new AutoTooltipLabel(Res.get("shared.pending")));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1393,7 +1393,7 @@ message SignedOffer {
|
||||||
message OpenOffer {
|
message OpenOffer {
|
||||||
enum State {
|
enum State {
|
||||||
PB_ERROR = 0;
|
PB_ERROR = 0;
|
||||||
SCHEDULED = 1;
|
PENDING = 1;
|
||||||
AVAILABLE = 2;
|
AVAILABLE = 2;
|
||||||
RESERVED = 3;
|
RESERVED = 3;
|
||||||
CLOSED = 4;
|
CLOSED = 4;
|
||||||
|
|
Loading…
Reference in a new issue