mirror of
https://github.com/haveno-dex/haveno.git
synced 2025-07-29 01:38:39 -04:00
fixes from congestion testing
- refactor main wallet polling - restart main wallet if connection changes before initial sync - use cached wallet state throughout app - avoid rescanning spent outputs until payout tx expected - allow payment sent/received buttons to be clicked until arrived - apply timeout to payment sent/received buttons - load DepositView asynchronously - remove separate timeout from OpenOffer - tolerate error importing multisig hex until necessary
This commit is contained in:
parent
9cbf042da2
commit
ca2d7704ab
22 changed files with 802 additions and 680 deletions
|
@ -607,7 +607,7 @@ public final class XmrConnectionService {
|
|||
long targetHeight = lastInfo.getTargetHeight();
|
||||
long blocksLeft = targetHeight - lastInfo.getHeight();
|
||||
if (syncStartHeight == null) syncStartHeight = lastInfo.getHeight();
|
||||
double percent = targetHeight == syncStartHeight ? 1.0 : ((double) Math.max(1, lastInfo.getHeight() - syncStartHeight) / (double) (targetHeight - syncStartHeight)) * 100d; // grant at least 1 block to show progress
|
||||
double percent = Math.min(1.0, targetHeight == syncStartHeight ? 1.0 : ((double) Math.max(1, lastInfo.getHeight() - syncStartHeight) / (double) (targetHeight - syncStartHeight))); // grant at least 1 block to show progress
|
||||
downloadListener.progress(percent, blocksLeft, null);
|
||||
}
|
||||
|
||||
|
|
|
@ -116,18 +116,16 @@ public class OfferBookService {
|
|||
@Override
|
||||
public void onAdded(Collection<ProtectedStorageEntry> protectedStorageEntries) {
|
||||
protectedStorageEntries.forEach(protectedStorageEntry -> {
|
||||
synchronized (offerBookChangedListeners) {
|
||||
offerBookChangedListeners.forEach(listener -> {
|
||||
if (protectedStorageEntry.getProtectedStoragePayload() instanceof OfferPayload) {
|
||||
OfferPayload offerPayload = (OfferPayload) protectedStorageEntry.getProtectedStoragePayload();
|
||||
maybeInitializeKeyImagePoller();
|
||||
keyImagePoller.addKeyImages(offerPayload.getReserveTxKeyImages());
|
||||
Offer offer = new Offer(offerPayload);
|
||||
offer.setPriceFeedService(priceFeedService);
|
||||
setReservedFundsSpent(offer);
|
||||
listener.onAdded(offer);
|
||||
}
|
||||
});
|
||||
if (protectedStorageEntry.getProtectedStoragePayload() instanceof OfferPayload) {
|
||||
OfferPayload offerPayload = (OfferPayload) protectedStorageEntry.getProtectedStoragePayload();
|
||||
maybeInitializeKeyImagePoller();
|
||||
keyImagePoller.addKeyImages(offerPayload.getReserveTxKeyImages());
|
||||
Offer offer = new Offer(offerPayload);
|
||||
offer.setPriceFeedService(priceFeedService);
|
||||
setReservedFundsSpent(offer);
|
||||
synchronized (offerBookChangedListeners) {
|
||||
offerBookChangedListeners.forEach(listener -> listener.onAdded(offer));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -135,18 +133,16 @@ public class OfferBookService {
|
|||
@Override
|
||||
public void onRemoved(Collection<ProtectedStorageEntry> protectedStorageEntries) {
|
||||
protectedStorageEntries.forEach(protectedStorageEntry -> {
|
||||
synchronized (offerBookChangedListeners) {
|
||||
offerBookChangedListeners.forEach(listener -> {
|
||||
if (protectedStorageEntry.getProtectedStoragePayload() instanceof OfferPayload) {
|
||||
OfferPayload offerPayload = (OfferPayload) protectedStorageEntry.getProtectedStoragePayload();
|
||||
maybeInitializeKeyImagePoller();
|
||||
keyImagePoller.removeKeyImages(offerPayload.getReserveTxKeyImages());
|
||||
Offer offer = new Offer(offerPayload);
|
||||
offer.setPriceFeedService(priceFeedService);
|
||||
setReservedFundsSpent(offer);
|
||||
listener.onRemoved(offer);
|
||||
}
|
||||
});
|
||||
if (protectedStorageEntry.getProtectedStoragePayload() instanceof OfferPayload) {
|
||||
OfferPayload offerPayload = (OfferPayload) protectedStorageEntry.getProtectedStoragePayload();
|
||||
maybeInitializeKeyImagePoller();
|
||||
keyImagePoller.removeKeyImages(offerPayload.getReserveTxKeyImages());
|
||||
Offer offer = new Offer(offerPayload);
|
||||
offer.setPriceFeedService(priceFeedService);
|
||||
setReservedFundsSpent(offer);
|
||||
synchronized (offerBookChangedListeners) {
|
||||
offerBookChangedListeners.forEach(listener -> listener.onRemoved(offer));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -34,8 +34,6 @@
|
|||
|
||||
package haveno.core.offer;
|
||||
|
||||
import haveno.common.Timer;
|
||||
import haveno.common.UserThread;
|
||||
import haveno.common.proto.ProtoUtil;
|
||||
import haveno.core.trade.Tradable;
|
||||
import javafx.beans.property.ObjectProperty;
|
||||
|
@ -55,9 +53,6 @@ import java.util.Optional;
|
|||
@EqualsAndHashCode
|
||||
@Slf4j
|
||||
public final class OpenOffer implements Tradable {
|
||||
// Timeout for offer reservation during takeoffer process. If deposit tx is not completed in that time we reset the offer to AVAILABLE state.
|
||||
private static final long TIMEOUT = 60;
|
||||
transient private Timer timeoutTimer;
|
||||
|
||||
public enum State {
|
||||
SCHEDULED,
|
||||
|
@ -227,13 +222,6 @@ public final class OpenOffer implements Tradable {
|
|||
public void setState(State state) {
|
||||
this.state = state;
|
||||
stateProperty.set(state);
|
||||
|
||||
// We keep it reserved for a limited time, if trade preparation fails we revert to available state
|
||||
if (this.state == State.RESERVED) { // TODO (woodser): remove this?
|
||||
startTimeout();
|
||||
} else {
|
||||
stopTimeout();
|
||||
}
|
||||
}
|
||||
|
||||
public ReadOnlyObjectProperty<State> stateProperty() {
|
||||
|
@ -252,26 +240,6 @@ public final class OpenOffer implements Tradable {
|
|||
return state == State.DEACTIVATED;
|
||||
}
|
||||
|
||||
private void startTimeout() {
|
||||
stopTimeout();
|
||||
|
||||
timeoutTimer = UserThread.runAfter(() -> {
|
||||
log.debug("Timeout for resetting State.RESERVED reached");
|
||||
if (state == State.RESERVED) {
|
||||
// we do not need to persist that as at startup any RESERVED state would be reset to AVAILABLE anyway
|
||||
setState(State.AVAILABLE);
|
||||
}
|
||||
}, TIMEOUT);
|
||||
}
|
||||
|
||||
private void stopTimeout() {
|
||||
if (timeoutTimer != null) {
|
||||
timeoutTimer.stop();
|
||||
timeoutTimer = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "OpenOffer{" +
|
||||
|
|
|
@ -971,8 +971,8 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
|
|||
// return if awaiting scheduled tx
|
||||
if (openOffer.getScheduledTxHashes() != null) return null;
|
||||
|
||||
// cache all transactions including from pool
|
||||
List<MoneroTxWallet> allTxs = xmrWalletService.getWallet().getTxs(new MoneroTxQuery().setIncludeOutputs(true));
|
||||
// get all transactions including from pool
|
||||
List<MoneroTxWallet> allTxs = xmrWalletService.getTransactions(false);
|
||||
|
||||
if (preferredSubaddressIndex != null) {
|
||||
|
||||
|
|
|
@ -766,6 +766,7 @@ public abstract class DisputeManager<T extends DisputeList<Dispute>> extends Sup
|
|||
trade.getSelf().getUpdatedMultisigHex(),
|
||||
receiver.getUnsignedPayoutTxHex(), // include dispute payout tx if arbitrator has their updated multisig info
|
||||
deferPublishPayout); // instruct trader to defer publishing payout tx because peer is expected to publish imminently
|
||||
receiverPeer.setDisputeClosedMessage(disputeClosedMessage);
|
||||
|
||||
// send dispute closed message
|
||||
log.info("Send {} to trader {}. tradeId={}, {}.uid={}, chatMessage.uid={}",
|
||||
|
|
|
@ -413,7 +413,7 @@ public abstract class Trade implements Tradable, Model {
|
|||
transient private Subscription tradeStateSubscription;
|
||||
transient private Subscription tradePhaseSubscription;
|
||||
transient private Subscription payoutStateSubscription;
|
||||
transient private TaskLooper txPollLooper;
|
||||
transient private TaskLooper pollLooper;
|
||||
transient private Long walletRefreshPeriodMs;
|
||||
transient private Long syncNormalStartTimeMs;
|
||||
|
||||
|
@ -890,6 +890,10 @@ public abstract class Trade implements Tradable, Model {
|
|||
|
||||
public void saveWallet() {
|
||||
synchronized (walletLock) {
|
||||
if (!walletExists()) {
|
||||
log.warn("Cannot save wallet for {} {} because it does not exist", getClass().getSimpleName(), getId());
|
||||
return;
|
||||
}
|
||||
if (wallet == null) throw new RuntimeException("Trade wallet is not open for trade " + getId());
|
||||
xmrWalletService.saveWallet(wallet);
|
||||
maybeBackupWallet();
|
||||
|
@ -1195,7 +1199,7 @@ public abstract class Trade implements Tradable, Model {
|
|||
return trader.getDepositTx();
|
||||
} catch (MoneroError e) {
|
||||
log.error("Error getting {} deposit tx {}: {}", getPeerRole(trader), depositId, e.getMessage()); // TODO: peer.getRole()
|
||||
return null;
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1264,9 +1268,12 @@ public abstract class Trade implements Tradable, Model {
|
|||
|
||||
// TODO: clear other process data
|
||||
setPayoutTxHex(null);
|
||||
for (TradePeer peer : getPeers()) {
|
||||
for (TradePeer peer : getAllTradeParties()) {
|
||||
peer.setUnsignedPayoutTxHex(null);
|
||||
peer.setUpdatedMultisigHex(null);
|
||||
peer.setDisputeClosedMessage(null);
|
||||
peer.setPaymentSentMessage(null);
|
||||
peer.setPaymentReceivedMessage(null);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1597,11 +1604,16 @@ public abstract class Trade implements Tradable, Model {
|
|||
}
|
||||
|
||||
private List<TradePeer> getPeers() {
|
||||
List<TradePeer> peers = getAllTradeParties();
|
||||
if (!peers.remove(getSelf())) throw new IllegalStateException("Failed to remove self from list of peers");
|
||||
return peers;
|
||||
}
|
||||
|
||||
private List<TradePeer> getAllTradeParties() {
|
||||
List<TradePeer> peers = new ArrayList<TradePeer>();
|
||||
peers.add(getMaker());
|
||||
peers.add(getTaker());
|
||||
peers.add(getArbitrator());
|
||||
if (!peers.remove(getSelf())) throw new IllegalStateException("Failed to remove self from list of peers");
|
||||
return peers;
|
||||
}
|
||||
|
||||
|
@ -1801,6 +1813,12 @@ public abstract class Trade implements Tradable, Model {
|
|||
return (isSeller() ? getBuyer() : getSeller()).getPaymentReceivedMessage() != null; // seller stores message to buyer and arbitrator, peers store message from seller
|
||||
}
|
||||
|
||||
public boolean hasDisputeClosedMessage() {
|
||||
|
||||
// arbitrator stores message to buyer and seller, peers store message from arbitrator
|
||||
return isArbitrator() ? getBuyer().getDisputeClosedMessage() != null || getSeller().getDisputeClosedMessage() != null : getArbitrator().getDisputeClosedMessage() != null;
|
||||
}
|
||||
|
||||
public boolean isPaymentReceived() {
|
||||
return getState().getPhase().ordinal() >= Phase.PAYMENT_RECEIVED.ordinal();
|
||||
}
|
||||
|
@ -1883,7 +1901,7 @@ public abstract class Trade implements Tradable, Model {
|
|||
public BigInteger getFrozenAmount() {
|
||||
BigInteger sum = BigInteger.ZERO;
|
||||
for (String keyImage : getSelf().getReserveTxKeyImages()) {
|
||||
List<MoneroOutputWallet> outputs = xmrWalletService.getWallet().getOutputs(new MoneroOutputQuery().setIsFrozen(true).setIsSpent(false).setKeyImage(new MoneroKeyImage(keyImage))); // TODO: will this check tx pool? avoid
|
||||
List<MoneroOutputWallet> outputs = xmrWalletService.getOutputs(new MoneroOutputQuery().setIsFrozen(true).setIsSpent(false).setKeyImage(new MoneroKeyImage(keyImage)));
|
||||
if (!outputs.isEmpty()) sum = sum.add(outputs.get(0).getAmount());
|
||||
}
|
||||
return sum;
|
||||
|
@ -2077,23 +2095,23 @@ public abstract class Trade implements Tradable, Model {
|
|||
synchronized (walletLock) {
|
||||
if (isShutDownStarted || isPollInProgress()) return;
|
||||
log.info("Starting to poll wallet for {} {}", getClass().getSimpleName(), getId());
|
||||
txPollLooper = new TaskLooper(() -> pollWallet());
|
||||
txPollLooper.start(walletRefreshPeriodMs);
|
||||
pollLooper = new TaskLooper(() -> pollWallet());
|
||||
pollLooper.start(walletRefreshPeriodMs);
|
||||
}
|
||||
}
|
||||
|
||||
private void stopPolling() {
|
||||
synchronized (walletLock) {
|
||||
if (isPollInProgress()) {
|
||||
txPollLooper.stop();
|
||||
txPollLooper = null;
|
||||
pollLooper.stop();
|
||||
pollLooper = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isPollInProgress() {
|
||||
synchronized (walletLock) {
|
||||
return txPollLooper != null;
|
||||
return pollLooper != null;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2117,8 +2135,14 @@ public abstract class Trade implements Tradable, Model {
|
|||
// skip if payout unlocked
|
||||
if (isPayoutUnlocked()) return;
|
||||
|
||||
// rescan spent outputs to detect payout tx after deposits unlocked
|
||||
if (isDepositsUnlocked() && !isPayoutPublished()) wallet.rescanSpent();
|
||||
// rescan spent outputs to detect unconfirmed payout tx after payment received message
|
||||
if (!isPayoutPublished() && (hasPaymentReceivedMessage() || hasDisputeClosedMessage())) {
|
||||
try {
|
||||
wallet.rescanSpent();
|
||||
} catch (Exception e) {
|
||||
log.warn("Error rescanning spent outputs to detect payout tx for {} {}, errorMessage={}", getClass().getSimpleName(), getShortId(), e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
// get txs from trade wallet
|
||||
boolean payoutExpected = isPaymentReceived() || getSeller().getPaymentReceivedMessage() != null || disputeState.ordinal() >= DisputeState.ARBITRATOR_SENT_DISPUTE_CLOSED_MSG.ordinal() || getArbitrator().getDisputeClosedMessage() != null;
|
||||
|
@ -2129,7 +2153,7 @@ public abstract class Trade implements Tradable, Model {
|
|||
|
||||
// warn on double spend // TODO: other handling?
|
||||
for (MoneroTxWallet tx : txs) {
|
||||
if (Boolean.TRUE.equals(tx.isDoubleSpendSeen())) log.warn("Double spend seen for tx {} for {} {}", tx.getHash(), getClass().getSimpleName(), getId());
|
||||
if (Boolean.TRUE.equals(tx.isDoubleSpendSeen())) log.warn("Double spend seen for tx {} for {} {}", tx.getHash(), getClass().getSimpleName(), getShortId());
|
||||
}
|
||||
|
||||
// check deposit txs
|
||||
|
@ -2189,9 +2213,8 @@ public abstract class Trade implements Tradable, Model {
|
|||
if (isConnectionRefused) forceRestartTradeWallet();
|
||||
else {
|
||||
boolean isWalletConnected = isWalletConnectedToDaemon();
|
||||
if (!isWalletConnected) xmrConnectionService.checkConnection(); // check connection if wallet is not connected
|
||||
if (!isShutDownStarted && wallet != null && isWalletConnected) {
|
||||
log.warn("Error polling trade wallet for {} {}: {}. Monerod={}", getClass().getSimpleName(), getId(), e.getMessage(), getXmrWalletService().getConnectionService().getConnection());
|
||||
log.warn("Error polling trade wallet for {} {}, errorMessage={}. Monerod={}", getClass().getSimpleName(), getShortId(), e.getMessage(), getXmrWalletService().getConnectionService().getConnection());
|
||||
//e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1287,7 +1287,7 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi
|
|||
}
|
||||
|
||||
private void removeTradeOnError(Trade trade) {
|
||||
log.warn("TradeManager.removeTradeOnError() tradeId={}, state={}", trade.getId(), trade.getState());
|
||||
log.warn("TradeManager.removeTradeOnError() trade={}, tradeId={}, state={}", trade.getClass().getSimpleName(), trade.getShortId(), trade.getState());
|
||||
synchronized (tradableList) {
|
||||
|
||||
// unreserve taker key images
|
||||
|
|
|
@ -134,14 +134,16 @@ public class BuyerProtocol extends DisputeProtocol {
|
|||
BuyerSendPaymentSentMessageToArbitrator.class)
|
||||
.using(new TradeTaskRunner(trade,
|
||||
() -> {
|
||||
stopTimeout();
|
||||
this.errorMessageHandler = null;
|
||||
resultHandler.handleResult();
|
||||
handleTaskRunnerSuccess(event);
|
||||
},
|
||||
(errorMessage) -> {
|
||||
handleTaskRunnerFault(event, errorMessage);
|
||||
})))
|
||||
.run(() -> trade.setState(Trade.State.BUYER_CONFIRMED_PAYMENT_SENT))
|
||||
}))
|
||||
.withTimeout(TradeProtocol.TRADE_TIMEOUT_SECONDS))
|
||||
.run(() -> trade.advanceState(Trade.State.BUYER_CONFIRMED_PAYMENT_SENT))
|
||||
.executeTasks(true);
|
||||
} catch (Exception e) {
|
||||
errorMessageHandler.handleErrorMessage("Error confirming payment sent: " + e.getMessage());
|
||||
|
|
|
@ -131,13 +131,15 @@ public class SellerProtocol extends DisputeProtocol {
|
|||
SellerSendPaymentReceivedMessageToBuyer.class,
|
||||
SellerSendPaymentReceivedMessageToArbitrator.class)
|
||||
.using(new TradeTaskRunner(trade, () -> {
|
||||
stopTimeout();
|
||||
this.errorMessageHandler = null;
|
||||
handleTaskRunnerSuccess(event);
|
||||
resultHandler.handleResult();
|
||||
}, (errorMessage) -> {
|
||||
handleTaskRunnerFault(event, errorMessage);
|
||||
})))
|
||||
.run(() -> trade.setState(Trade.State.SELLER_CONFIRMED_PAYMENT_RECEIPT))
|
||||
}))
|
||||
.withTimeout(TradeProtocol.TRADE_TIMEOUT_SECONDS))
|
||||
.run(() -> trade.advanceState(Trade.State.SELLER_CONFIRMED_PAYMENT_RECEIPT))
|
||||
.executeTasks(true);
|
||||
} catch (Exception e) {
|
||||
errorMessageHandler.handleErrorMessage("Error confirming payment received: " + e.getMessage());
|
||||
|
|
|
@ -61,13 +61,17 @@ public class ProcessDepositsConfirmedMessage extends TradeTask {
|
|||
log.info(trade.getClass().getSimpleName() + " decrypting using seller payment account key");
|
||||
trade.decryptPeerPaymentAccountPayload(request.getSellerPaymentAccountKey());
|
||||
}
|
||||
processModel.getTradeManager().requestPersistence(); // in case importing multisig hex fails
|
||||
|
||||
// import multisig hex
|
||||
trade.importMultisigHex();
|
||||
|
||||
// persist and complete
|
||||
// persist
|
||||
processModel.getTradeManager().requestPersistence();
|
||||
|
||||
// try to import multisig hex (retry later)
|
||||
try {
|
||||
trade.importMultisigHex();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
complete();
|
||||
} catch (Throwable t) {
|
||||
failed(t);
|
||||
|
|
|
@ -95,7 +95,6 @@ public class ProcessPaymentReceivedMessage extends TradeTask {
|
|||
}
|
||||
trade.requestPersistence();
|
||||
|
||||
|
||||
// process payout tx unless already unlocked
|
||||
if (!trade.isPayoutUnlocked()) processPayoutTx(message);
|
||||
|
||||
|
|
|
@ -61,8 +61,12 @@ public class ProcessPaymentSentMessage extends TradeTask {
|
|||
if (trade.isSeller()) trade.decryptPeerPaymentAccountPayload(message.getPaymentAccountKey());
|
||||
trade.requestPersistence();
|
||||
|
||||
// import multisig hex
|
||||
trade.importMultisigHex();
|
||||
// try to import multisig hex (retry later)
|
||||
try {
|
||||
trade.importMultisigHex();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
// update state
|
||||
trade.advanceState(Trade.State.BUYER_SENT_PAYMENT_SENT_MSG);
|
||||
|
|
|
@ -1,71 +0,0 @@
|
|||
/*
|
||||
* This file is part of Bisq.
|
||||
*
|
||||
* Bisq is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* Bisq is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with Bisq. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package haveno.core.trade.protocol.tasks;
|
||||
|
||||
import haveno.common.taskrunner.TaskRunner;
|
||||
import haveno.core.trade.Trade;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
public class SellerPublishDepositTx extends TradeTask {
|
||||
public SellerPublishDepositTx(TaskRunner<Trade> taskHandler, Trade trade) {
|
||||
super(taskHandler, trade);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void run() {
|
||||
try {
|
||||
runInterceptHook();
|
||||
throw new RuntimeException("SellerPublishesDepositTx not implemented for xmr");
|
||||
|
||||
// final Transaction depositTx = processModel.getDepositTx();
|
||||
// processModel.getTradeWalletService().broadcastTx(depositTx,
|
||||
// new TxBroadcaster.Callback() {
|
||||
// @Override
|
||||
// public void onSuccess(Transaction transaction) {
|
||||
// if (!completed) {
|
||||
// // Now as we have published the deposit tx we set it in trade
|
||||
// trade.applyDepositTx(depositTx);
|
||||
//
|
||||
// trade.setState(Trade.State.SELLER_PUBLISHED_DEPOSIT_TX);
|
||||
//
|
||||
// processModel.getBtcWalletService().swapAddressEntryToAvailable(processModel.getOffer().getId(),
|
||||
// AddressEntry.Context.RESERVED_FOR_TRADE);
|
||||
//
|
||||
// processModel.getTradeManager().requestPersistence();
|
||||
//
|
||||
// complete();
|
||||
// } else {
|
||||
// log.warn("We got the onSuccess callback called after the timeout has been triggered a complete().");
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void onFailure(TxBroadcastException exception) {
|
||||
// if (!completed) {
|
||||
// failed(exception);
|
||||
// } else {
|
||||
// log.warn("We got the onFailure callback called after the timeout has been triggered a complete().");
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
} catch (Throwable t) {
|
||||
failed(t);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -140,7 +140,7 @@ public class Balances {
|
|||
// calculate reserved offer balance
|
||||
reservedOfferBalance = BigInteger.ZERO;
|
||||
if (xmrWalletService.getWallet() != null) {
|
||||
List<MoneroOutputWallet> frozenOutputs = xmrWalletService.getWallet().getOutputs(new MoneroOutputQuery().setIsFrozen(true).setIsSpent(false));
|
||||
List<MoneroOutputWallet> frozenOutputs = xmrWalletService.getOutputs(new MoneroOutputQuery().setIsFrozen(true).setIsSpent(false));
|
||||
for (MoneroOutputWallet frozenOutput : frozenOutputs) reservedOfferBalance = reservedOfferBalance.add(frozenOutput.getAmount());
|
||||
}
|
||||
for (Trade trade : trades) {
|
||||
|
|
|
@ -11,7 +11,7 @@ public class DownloadListener {
|
|||
private final DoubleProperty percentage = new SimpleDoubleProperty(-1);
|
||||
|
||||
public void progress(double percentage, long blocksLeft, Date date) {
|
||||
UserThread.await(() -> this.percentage.set(percentage / 100d));
|
||||
UserThread.await(() -> this.percentage.set(percentage));
|
||||
}
|
||||
|
||||
public void doneDownload() {
|
||||
|
|
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue