mirror of
https://github.com/haveno-dex/haveno.git
synced 2024-12-24 23:09:36 -05:00
set deposit tx confirmations from wallet instead of daemon request
This commit is contained in:
parent
f0862b7aeb
commit
adccf27385
@ -73,11 +73,13 @@ import haveno.network.p2p.AckMessage;
|
||||
import haveno.network.p2p.NodeAddress;
|
||||
import haveno.network.p2p.P2PService;
|
||||
import javafx.beans.property.DoubleProperty;
|
||||
import javafx.beans.property.IntegerProperty;
|
||||
import javafx.beans.property.ObjectProperty;
|
||||
import javafx.beans.property.ReadOnlyDoubleProperty;
|
||||
import javafx.beans.property.ReadOnlyObjectProperty;
|
||||
import javafx.beans.property.ReadOnlyStringProperty;
|
||||
import javafx.beans.property.SimpleDoubleProperty;
|
||||
import javafx.beans.property.SimpleIntegerProperty;
|
||||
import javafx.beans.property.SimpleObjectProperty;
|
||||
import javafx.beans.property.SimpleStringProperty;
|
||||
import javafx.beans.property.StringProperty;
|
||||
@ -408,6 +410,8 @@ public abstract class Trade implements Tradable, Model {
|
||||
transient final private ObjectProperty<PayoutState> payoutStateProperty = new SimpleObjectProperty<>(payoutState);
|
||||
transient final private ObjectProperty<DisputeState> disputeStateProperty = new SimpleObjectProperty<>(disputeState);
|
||||
transient final private ObjectProperty<TradePeriodState> tradePeriodStateProperty = new SimpleObjectProperty<>(periodState);
|
||||
@Getter
|
||||
transient public final IntegerProperty depositTxsUpdateCounter = new SimpleIntegerProperty(0);
|
||||
transient final private StringProperty errorMessageProperty = new SimpleStringProperty();
|
||||
transient private Subscription tradeStateSubscription;
|
||||
transient private Subscription tradePhaseSubscription;
|
||||
@ -2028,7 +2032,7 @@ public abstract class Trade implements Tradable, Model {
|
||||
}
|
||||
|
||||
private void tryInitPollingAux() {
|
||||
if (!wasWalletSynced) trySyncWallet(false);
|
||||
if (!wasWalletSynced) trySyncWallet(true);
|
||||
updatePollPeriod();
|
||||
|
||||
// reprocess pending payout messages
|
||||
@ -2135,9 +2139,12 @@ public abstract class Trade implements Tradable, Model {
|
||||
syncWalletIfBehind();
|
||||
|
||||
// get txs from trade wallet
|
||||
List<MoneroTxWallet> txs = wallet.getTxs(new MoneroTxQuery().setIncludeOutputs(true).setInTxPool(false)); // TODO (monero-wallet-rpc): cannot get pool txs without re-refetching from pool
|
||||
MoneroTxQuery query = new MoneroTxQuery().setIncludeOutputs(true);
|
||||
Boolean updatePool = !isDepositsConfirmed() && (getMaker().getDepositTx() == null || getTaker().getDepositTx() == null);
|
||||
if (!updatePool) query.setInTxPool(false); // avoid updating from pool if possible
|
||||
List<MoneroTxWallet> txs = wallet.getTxs(query);
|
||||
setDepositTxs(txs);
|
||||
if (txs.size() != 2) return; // skip if either tx not seen
|
||||
if (getMaker().getDepositTx() == null || getTaker().getDepositTx() == null) return; // skip if either deposit tx not seen
|
||||
setStateDepositsSeen();
|
||||
|
||||
// set actual security deposits
|
||||
@ -2176,9 +2183,9 @@ public abstract class Trade implements Tradable, Model {
|
||||
}
|
||||
|
||||
// get txs from trade wallet
|
||||
boolean checkPool = isPayoutExpected && !isPayoutConfirmed();
|
||||
MoneroTxQuery query = new MoneroTxQuery().setIncludeOutputs(true);
|
||||
if (!checkPool) query.setInTxPool(false); // avoid pool check if possible
|
||||
boolean updatePool = isPayoutExpected && !isPayoutConfirmed();
|
||||
if (!updatePool) query.setInTxPool(false); // avoid updating from pool if possible
|
||||
List<MoneroTxWallet> txs = wallet.getTxs(query);
|
||||
setDepositTxs(txs);
|
||||
|
||||
@ -2224,6 +2231,7 @@ public abstract class Trade implements Tradable, Model {
|
||||
if (tx.getHash().equals(getMaker().getDepositTxHash())) getMaker().setDepositTx(tx);
|
||||
if (tx.getHash().equals(getTaker().getDepositTxHash())) getTaker().setDepositTx(tx);
|
||||
}
|
||||
if (!txs.isEmpty()) depositTxsUpdateCounter.set(depositTxsUpdateCounter.get() + 1);
|
||||
}
|
||||
|
||||
private void forceRestartTradeWallet() {
|
||||
|
@ -1775,7 +1775,7 @@ public class XmrWalletService {
|
||||
if (wallet.getHeight() < xmrConnectionService.getTargetHeight()) wallet.sync();
|
||||
|
||||
// fetch transactions from pool and store to cache
|
||||
// TODO: ideally wallet should sync every poll and then avoid checking pool on fetching txs
|
||||
// TODO: ideally wallet should sync every poll and then avoid updating from pool on fetching txs
|
||||
if (updateTxs) {
|
||||
try {
|
||||
cachedTxs = wallet.getTxs(new MoneroTxQuery().setIncludeOutputs(true));
|
||||
|
@ -23,11 +23,13 @@ import de.jensd.fx.fontawesome.AwesomeIcon;
|
||||
import haveno.common.UserThread;
|
||||
import haveno.common.util.Utilities;
|
||||
import haveno.core.locale.Res;
|
||||
import haveno.core.trade.Trade;
|
||||
import haveno.core.user.BlockChainExplorer;
|
||||
import haveno.core.user.Preferences;
|
||||
import haveno.core.xmr.wallet.XmrWalletService;
|
||||
import haveno.desktop.components.indicator.TxConfidenceIndicator;
|
||||
import haveno.desktop.util.GUIUtil;
|
||||
import javafx.beans.value.ChangeListener;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.TextField;
|
||||
import javafx.scene.control.Tooltip;
|
||||
@ -51,7 +53,9 @@ public class TxIdTextField extends AnchorPane {
|
||||
private final TxConfidenceIndicator txConfidenceIndicator;
|
||||
private final Label copyIcon, blockExplorerIcon, missingTxWarningIcon;
|
||||
|
||||
private MoneroWalletListener txUpdater;
|
||||
private MoneroWalletListener walletListener;
|
||||
private ChangeListener<Number> tradeListener;
|
||||
private Trade trade;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Constructor
|
||||
@ -108,9 +112,18 @@ public class TxIdTextField extends AnchorPane {
|
||||
}
|
||||
|
||||
public void setup(@Nullable String txId) {
|
||||
if (txUpdater != null) {
|
||||
xmrWalletService.removeWalletListener(txUpdater);
|
||||
txUpdater = null;
|
||||
setup(txId, null);
|
||||
}
|
||||
|
||||
public void setup(@Nullable String txId, Trade trade) {
|
||||
this.trade = trade;
|
||||
if (walletListener != null) {
|
||||
xmrWalletService.removeWalletListener(walletListener);
|
||||
walletListener = null;
|
||||
}
|
||||
if (tradeListener != null) {
|
||||
trade.getDepositTxsUpdateCounter().removeListener(tradeListener);
|
||||
tradeListener = null;
|
||||
}
|
||||
|
||||
if (txId == null) {
|
||||
@ -126,15 +139,21 @@ public class TxIdTextField extends AnchorPane {
|
||||
return;
|
||||
}
|
||||
|
||||
// listen for tx updates
|
||||
// TODO: this only listens for new blocks, listen for double spend
|
||||
txUpdater = new MoneroWalletListener() {
|
||||
@Override
|
||||
public void onNewBlock(long lastBlockHeight) {
|
||||
updateConfidence(txId, false, lastBlockHeight);
|
||||
}
|
||||
};
|
||||
xmrWalletService.addWalletListener(txUpdater);
|
||||
// subscribe for tx updates
|
||||
if (trade == null) {
|
||||
walletListener = new MoneroWalletListener() {
|
||||
@Override
|
||||
public void onNewBlock(long height) {
|
||||
updateConfidence(txId, trade, false, height);
|
||||
}
|
||||
};
|
||||
xmrWalletService.addWalletListener(walletListener); // TODO: this only listens for new blocks, listen for double spend
|
||||
} else {
|
||||
tradeListener = (observable, oldValue, newValue) -> {
|
||||
updateConfidence(txId, trade, null, null);
|
||||
};
|
||||
trade.getDepositTxsUpdateCounter().addListener(tradeListener);
|
||||
}
|
||||
|
||||
textField.setText(txId);
|
||||
textField.setOnMouseClicked(mouseEvent -> openBlockExplorer(txId));
|
||||
@ -143,14 +162,19 @@ public class TxIdTextField extends AnchorPane {
|
||||
txConfidenceIndicator.setVisible(true);
|
||||
|
||||
// update off main thread
|
||||
new Thread(() -> updateConfidence(txId, true, null)).start();
|
||||
new Thread(() -> updateConfidence(txId, trade, true, null)).start();
|
||||
}
|
||||
|
||||
public void cleanup() {
|
||||
if (xmrWalletService != null && txUpdater != null) {
|
||||
xmrWalletService.removeWalletListener(txUpdater);
|
||||
txUpdater = null;
|
||||
if (xmrWalletService != null && walletListener != null) {
|
||||
xmrWalletService.removeWalletListener(walletListener);
|
||||
walletListener = null;
|
||||
}
|
||||
if (tradeListener != null) {
|
||||
trade.getDepositTxsUpdateCounter().removeListener(tradeListener);
|
||||
tradeListener = null;
|
||||
}
|
||||
trade = null;
|
||||
textField.setOnMouseClicked(null);
|
||||
blockExplorerIcon.setOnMouseClicked(null);
|
||||
copyIcon.setOnMouseClicked(null);
|
||||
@ -168,11 +192,16 @@ public class TxIdTextField extends AnchorPane {
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized void updateConfidence(String txId, boolean useCache, Long height) {
|
||||
private synchronized void updateConfidence(String txId, Trade trade, Boolean useCache, Long height) {
|
||||
MoneroTx tx = null;
|
||||
try {
|
||||
tx = useCache ? xmrWalletService.getDaemonTxWithCache(txId) : xmrWalletService.getDaemonTx(txId);
|
||||
tx.setNumConfirmations(tx.isConfirmed() ? (height == null ? xmrWalletService.getConnectionService().getLastInfo().getHeight() : height) - tx.getHeight(): 0l); // TODO: don't set if tx.getNumConfirmations() works reliably on non-local testnet
|
||||
if (trade == null) {
|
||||
tx = useCache ? xmrWalletService.getDaemonTxWithCache(txId) : xmrWalletService.getDaemonTx(txId);
|
||||
tx.setNumConfirmations(tx.isConfirmed() ? (height == null ? xmrWalletService.getConnectionService().getLastInfo().getHeight() : height) - tx.getHeight(): 0l); // TODO: don't set if tx.getNumConfirmations() works reliably on non-local testnet
|
||||
} else {
|
||||
if (txId.equals(trade.getMaker().getDepositTxHash())) tx = trade.getMaker().getDepositTx();
|
||||
else if (txId.equals(trade.getTaker().getDepositTxHash())) tx = trade.getTaker().getDepositTx();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// do nothing
|
||||
}
|
||||
@ -185,9 +214,9 @@ public class TxIdTextField extends AnchorPane {
|
||||
if (txConfidenceIndicator.getProgress() != 0) {
|
||||
AnchorPane.setRightAnchor(txConfidenceIndicator, 0.0);
|
||||
}
|
||||
if (txConfidenceIndicator.getProgress() >= 1.0 && txUpdater != null) {
|
||||
xmrWalletService.removeWalletListener(txUpdater); // unregister listener
|
||||
txUpdater = null;
|
||||
if (txConfidenceIndicator.getProgress() >= 1.0 && walletListener != null) {
|
||||
xmrWalletService.removeWalletListener(walletListener); // unregister listener
|
||||
walletListener = null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -325,8 +325,10 @@ public class PendingTradesView extends ActivatableViewAndModel<VBox, PendingTrad
|
||||
|
||||
selectedTableItemSubscription = EasyBind.subscribe(tableView.getSelectionModel().selectedItemProperty(),
|
||||
selectedItem -> {
|
||||
if (selectedItem != null && !selectedItem.equals(model.dataModel.selectedItemProperty.get()))
|
||||
if (selectedItem != null && !selectedItem.equals(model.dataModel.selectedItemProperty.get())) {
|
||||
if (selectedSubView != null) selectedSubView.deactivate();
|
||||
model.dataModel.onSelectItem(selectedItem);
|
||||
}
|
||||
});
|
||||
|
||||
updateTableSelection();
|
||||
|
@ -52,8 +52,6 @@ import haveno.desktop.util.Layout;
|
||||
import haveno.network.p2p.BootstrapListener;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.property.BooleanProperty;
|
||||
@ -110,8 +108,6 @@ public abstract class TradeStepView extends AnchorPane {
|
||||
trade = model.dataModel.getTrade();
|
||||
checkNotNull(trade, "Trade must not be null at TradeStepView");
|
||||
|
||||
startCachingTxs();
|
||||
|
||||
ScrollPane scrollPane = new ScrollPane();
|
||||
scrollPane.setHbarPolicy(ScrollPane.ScrollBarPolicy.NEVER);
|
||||
scrollPane.setVbarPolicy(ScrollPane.ScrollBarPolicy.AS_NEEDED);
|
||||
@ -167,13 +163,6 @@ public abstract class TradeStepView extends AnchorPane {
|
||||
// };
|
||||
}
|
||||
|
||||
private void startCachingTxs() {
|
||||
List<String> txIds = new ArrayList<String>();
|
||||
if (!model.dataModel.makerTxId.isEmpty().get()) txIds.add(model.dataModel.makerTxId.get());
|
||||
if (!model.dataModel.takerTxId.isEmpty().get()) txIds.add(model.dataModel.takerTxId.get());
|
||||
new Thread(() -> trade.getXmrWalletService().getDaemonTxsWithCache(txIds)).start();
|
||||
}
|
||||
|
||||
public void activate() {
|
||||
if (selfTxIdTextField != null) {
|
||||
if (selfTxIdSubscription != null)
|
||||
@ -181,8 +170,7 @@ public abstract class TradeStepView extends AnchorPane {
|
||||
|
||||
selfTxIdSubscription = EasyBind.subscribe(model.dataModel.isMaker() ? model.dataModel.makerTxId : model.dataModel.takerTxId, id -> {
|
||||
if (!id.isEmpty()) {
|
||||
startCachingTxs();
|
||||
selfTxIdTextField.setup(id);
|
||||
selfTxIdTextField.setup(id, trade);
|
||||
} else {
|
||||
selfTxIdTextField.cleanup();
|
||||
}
|
||||
@ -194,8 +182,7 @@ public abstract class TradeStepView extends AnchorPane {
|
||||
|
||||
peerTxIdSubscription = EasyBind.subscribe(model.dataModel.isMaker() ? model.dataModel.takerTxId : model.dataModel.makerTxId, id -> {
|
||||
if (!id.isEmpty()) {
|
||||
startCachingTxs();
|
||||
peerTxIdTextField.setup(id);
|
||||
peerTxIdTextField.setup(id, trade);
|
||||
} else {
|
||||
peerTxIdTextField.cleanup();
|
||||
}
|
||||
@ -350,7 +337,7 @@ public abstract class TradeStepView extends AnchorPane {
|
||||
|
||||
String selfTxId = model.dataModel.isMaker() ? model.dataModel.makerTxId.get() : model.dataModel.takerTxId.get();
|
||||
if (!selfTxId.isEmpty())
|
||||
selfTxIdTextField.setup(selfTxId);
|
||||
selfTxIdTextField.setup(selfTxId, trade);
|
||||
else
|
||||
selfTxIdTextField.cleanup();
|
||||
|
||||
@ -364,7 +351,7 @@ public abstract class TradeStepView extends AnchorPane {
|
||||
|
||||
String peerTxId = model.dataModel.isMaker() ? model.dataModel.takerTxId.get() : model.dataModel.makerTxId.get();
|
||||
if (!peerTxId.isEmpty())
|
||||
peerTxIdTextField.setup(peerTxId);
|
||||
peerTxIdTextField.setup(peerTxId, trade);
|
||||
else
|
||||
peerTxIdTextField.cleanup();
|
||||
|
||||
|
@ -528,18 +528,20 @@ public class GUIUtil {
|
||||
public static void updateConfidence(MoneroTx tx,
|
||||
Tooltip tooltip,
|
||||
TxConfidenceIndicator txConfidenceIndicator) {
|
||||
if (tx != null && (tx.getNumConfirmations() == null || !tx.isRelayed())) {
|
||||
if (tx == null || tx.getNumConfirmations() == null || !tx.isRelayed()) {
|
||||
tooltip.setText(Res.get("confidence.unknown"));
|
||||
txConfidenceIndicator.setProgress(0);
|
||||
} else if (tx != null && tx.isFailed()) {
|
||||
tooltip.setText(Res.get("confidence.invalid"));
|
||||
txConfidenceIndicator.setProgress(0);
|
||||
} else if (tx != null && tx.isConfirmed()) {
|
||||
tooltip.setText(Res.get("confidence.confirmed", tx.getNumConfirmations()));
|
||||
txConfidenceIndicator.setProgress((double) tx.getNumConfirmations() / (double) XmrWalletService.NUM_BLOCKS_UNLOCK);
|
||||
txConfidenceIndicator.setProgress(-1);
|
||||
} else {
|
||||
tooltip.setText(Res.get("confidence.seen", 0)); // TODO: replace with numBroadcastPeers
|
||||
txConfidenceIndicator.setProgress(-1.0);
|
||||
if (tx.isFailed()) {
|
||||
tooltip.setText(Res.get("confidence.invalid"));
|
||||
txConfidenceIndicator.setProgress(0);
|
||||
} else if (tx.isConfirmed()) {
|
||||
tooltip.setText(Res.get("confidence.confirmed", tx.getNumConfirmations()));
|
||||
txConfidenceIndicator.setProgress((double) tx.getNumConfirmations() / (double) XmrWalletService.NUM_BLOCKS_UNLOCK);
|
||||
} else {
|
||||
tooltip.setText(Res.get("confidence.seen", 0));
|
||||
txConfidenceIndicator.setProgress(-1);
|
||||
}
|
||||
}
|
||||
|
||||
txConfidenceIndicator.setPrefSize(24, 24);
|
||||
|
Loading…
Reference in New Issue
Block a user