mirror of
https://github.com/haveno-dex/haveno.git
synced 2024-10-01 01:35:48 -04:00
fix 'trade not found' bug caused by open offer being spent
do not remove open offer with spent funds if reserved for trade fix concurrent modification exception
This commit is contained in:
parent
266d129462
commit
cd7f176e2b
@ -225,7 +225,7 @@ class CoreTradesService {
|
||||
}
|
||||
|
||||
private Optional<Trade> getClosedTrade(String tradeId) {
|
||||
Optional<Tradable> tradable = closedTradableManager.getTradableById(tradeId);
|
||||
Optional<Tradable> tradable = closedTradableManager.getTradeById(tradeId);
|
||||
return tradable.filter((t) -> t instanceof Trade).map(value -> (Trade) value);
|
||||
}
|
||||
|
||||
|
@ -196,7 +196,7 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
|
||||
@Override
|
||||
public void onAdded(Offer offer) {
|
||||
Optional<OpenOffer> openOfferOptional = getOpenOfferById(offer.getId());
|
||||
if (openOfferOptional.isPresent() && offer.isReservedFundsSpent()) {
|
||||
if (openOfferOptional.isPresent() && openOfferOptional.get().getState() != OpenOffer.State.RESERVED && offer.isReservedFundsSpent()) {
|
||||
removeOpenOffer(openOfferOptional.get(), null);
|
||||
}
|
||||
}
|
||||
@ -247,8 +247,8 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
|
||||
// .ifPresent(errorMsg -> invalidOffers.add(new Tuple2<>(openOffer, errorMsg))));
|
||||
|
||||
// process unposted offers
|
||||
processUnpostedOffers((transaction) -> {}, (errMessage) -> {
|
||||
log.warn("Error processing unposted offers on new unlocked balance: " + errMessage);
|
||||
processUnpostedOffers((transaction) -> {}, (errorMessage) -> {
|
||||
log.warn("Error processing unposted offers on new unlocked balance: " + errorMessage);
|
||||
});
|
||||
|
||||
// register to process unposted offers when unlocked balance increases
|
||||
@ -257,8 +257,8 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
|
||||
@Override
|
||||
public void onBalancesChanged(BigInteger newBalance, BigInteger newUnlockedBalance) {
|
||||
if (lastUnlockedBalance == null || lastUnlockedBalance.compareTo(newUnlockedBalance) < 0) {
|
||||
processUnpostedOffers((transaction) -> {}, (errMessage) -> {
|
||||
log.warn("Error processing unposted offers on new unlocked balance: " + errMessage);
|
||||
processUnpostedOffers((transaction) -> {}, (errorMessage) -> {
|
||||
log.warn("Error processing unposted offers on new unlocked balance: " + errorMessage);
|
||||
});
|
||||
}
|
||||
lastUnlockedBalance = newUnlockedBalance;
|
||||
@ -327,6 +327,7 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
|
||||
List<OpenOffer> openOffersList = new ArrayList<>(openOffers);
|
||||
openOffersList.forEach(openOffer -> removeOpenOffer(openOffer, () -> {
|
||||
}, errorMessage -> {
|
||||
log.warn("Error removing open offer: " + errorMessage);
|
||||
}));
|
||||
if (completeHandler != null)
|
||||
UserThread.runAfter(completeHandler, size * 200 + 500, TimeUnit.MILLISECONDS);
|
||||
@ -448,10 +449,11 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
|
||||
addOpenOffer(openOffer);
|
||||
requestPersistence();
|
||||
resultHandler.handleResult(transaction);
|
||||
}, (errMessage) -> {
|
||||
}, (errorMessage) -> {
|
||||
log.warn("Error processing unposted offer {}: {}", openOffer.getId(), errorMessage);
|
||||
onRemoved(openOffer);
|
||||
offer.setErrorMessage(errMessage);
|
||||
errorMessageHandler.handleErrorMessage(errMessage);
|
||||
offer.setErrorMessage(errorMessage);
|
||||
errorMessageHandler.handleErrorMessage(errorMessage);
|
||||
});
|
||||
}
|
||||
|
||||
@ -691,6 +693,7 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
|
||||
processUnpostedOffer(openOffers, scheduledOffer, (transaction) -> {
|
||||
latch.countDown();
|
||||
}, errorMessage -> {
|
||||
log.warn("Error processing unposted offer {}: {}", scheduledOffer.getId(), errorMessage);
|
||||
onRemoved(scheduledOffer);
|
||||
errorMessages.add(errorMessage);
|
||||
latch.countDown();
|
||||
|
@ -151,6 +151,10 @@ public class ClosedTradableManager implements PersistedDataHost {
|
||||
return closedTradables.stream().filter(e -> e.getId().equals(id)).findFirst();
|
||||
}
|
||||
|
||||
public Optional<Tradable> getTradeById(String id) {
|
||||
return closedTradables.stream().filter(e -> e instanceof Trade && e.getId().equals(id)).findFirst();
|
||||
}
|
||||
|
||||
public void maybeClearSensitiveData() {
|
||||
log.info("checking closed trades eligibility for having sensitive data cleared");
|
||||
closedTradables.stream()
|
||||
|
@ -20,7 +20,6 @@ package bisq.core.trade;
|
||||
import bisq.core.monetary.Price;
|
||||
import bisq.core.monetary.Volume;
|
||||
import bisq.core.offer.Offer;
|
||||
import bisq.core.trade.protocol.TradingPeer;
|
||||
import bisq.network.p2p.NodeAddress;
|
||||
|
||||
import bisq.common.proto.persistable.PersistablePayload;
|
||||
|
@ -895,11 +895,14 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi
|
||||
}
|
||||
|
||||
public Stream<Trade> getTradesStreamWithFundsLockedIn() {
|
||||
synchronized (tradableList) {
|
||||
return getObservableList().stream().filter(Trade::isFundsLockedIn);
|
||||
}
|
||||
}
|
||||
|
||||
public Set<String> getSetOfFailedOrClosedTradeIdsFromLockedInFunds() throws TradeTxException {
|
||||
AtomicReference<TradeTxException> tradeTxException = new AtomicReference<>();
|
||||
synchronized (tradableList) {
|
||||
Set<String> tradesIdSet = getTradesStreamWithFundsLockedIn()
|
||||
.filter(Trade::hasFailed)
|
||||
.map(Trade::getId)
|
||||
@ -948,6 +951,7 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi
|
||||
|
||||
return tradesIdSet;
|
||||
}
|
||||
}
|
||||
|
||||
// If trade still has funds locked up it might come back from failed trades
|
||||
// Aborts unfailing if the address entries needed are not available
|
||||
@ -1028,11 +1032,13 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi
|
||||
}
|
||||
|
||||
public List<Trade> getOpenTrades() {
|
||||
synchronized (tradableList) {
|
||||
return ImmutableList.copyOf(getObservableList().stream()
|
||||
.filter(e -> e instanceof Trade)
|
||||
.map(e -> e)
|
||||
.collect(Collectors.toList()));
|
||||
}
|
||||
}
|
||||
|
||||
public Optional<Trade> getClosedTrade(String tradeId) {
|
||||
return closedTradableManager.getClosedTrades().stream().filter(e -> e.getId().equals(tradeId)).findFirst();
|
||||
|
@ -87,6 +87,7 @@ class GrpcTradesService extends TradesImplBase {
|
||||
} catch (IllegalArgumentException cause) {
|
||||
// Offer makers may call 'gettrade' many times before a trade exists.
|
||||
// Log a 'trade not found' warning instead of a full stack trace.
|
||||
cause.printStackTrace();
|
||||
exceptionHandler.handleExceptionAsWarning(log, "getTrade", cause, responseObserver);
|
||||
} catch (Throwable cause) {
|
||||
exceptionHandler.handleException(log, cause, responseObserver);
|
||||
|
@ -20,7 +20,6 @@ package bisq.desktop.main.portfolio.closedtrades;
|
||||
import bisq.desktop.common.model.ActivatableWithDataModel;
|
||||
import bisq.desktop.common.model.ViewModel;
|
||||
|
||||
import bisq.core.monetary.Volume;
|
||||
import bisq.core.trade.ClosedTradableFormatter;
|
||||
|
||||
import org.bitcoinj.core.Coin;
|
||||
|
Loading…
Reference in New Issue
Block a user