mirror of
https://github.com/haveno-dex/haveno.git
synced 2025-08-09 23:22:16 -04:00
stability fixes on tor
optimize when multisig info imported fetch updates for tx progress indicators off main thread add synchronization locks refactor address entry management add totalTxFee to process model prevent same user from taking same offer at same time set refresh rate to 30s for tor
This commit is contained in:
parent
36cf91e093
commit
1b753e4f29
33 changed files with 498 additions and 354 deletions
|
@ -20,6 +20,7 @@ package haveno.desktop.components;
|
|||
import com.jfoenix.controls.JFXTextField;
|
||||
import de.jensd.fx.fontawesome.AwesomeDude;
|
||||
import de.jensd.fx.fontawesome.AwesomeIcon;
|
||||
import haveno.common.UserThread;
|
||||
import haveno.common.util.Utilities;
|
||||
import haveno.core.locale.Res;
|
||||
import haveno.core.user.BlockChainExplorer;
|
||||
|
@ -135,12 +136,14 @@ public class TxIdTextField extends AnchorPane {
|
|||
};
|
||||
xmrWalletService.addWalletListener(txUpdater);
|
||||
|
||||
updateConfidence(txId, true, null);
|
||||
|
||||
textField.setText(txId);
|
||||
textField.setOnMouseClicked(mouseEvent -> openBlockExplorer(txId));
|
||||
blockExplorerIcon.setOnMouseClicked(mouseEvent -> openBlockExplorer(txId));
|
||||
copyIcon.setOnMouseClicked(e -> Utilities.copyToClipboard(txId));
|
||||
txConfidenceIndicator.setVisible(true);
|
||||
|
||||
// update off main thread
|
||||
new Thread(() -> updateConfidence(txId, true, null)).start();
|
||||
}
|
||||
|
||||
public void cleanup() {
|
||||
|
@ -165,7 +168,7 @@ public class TxIdTextField extends AnchorPane {
|
|||
}
|
||||
}
|
||||
|
||||
private void updateConfidence(String txId, boolean useCache, Long height) {
|
||||
private synchronized void updateConfidence(String txId, boolean useCache, Long height) {
|
||||
MoneroTx tx = null;
|
||||
try {
|
||||
tx = useCache ? xmrWalletService.getTxWithCache(txId) : xmrWalletService.getTx(txId);
|
||||
|
@ -173,14 +176,19 @@ public class TxIdTextField extends AnchorPane {
|
|||
} catch (Exception e) {
|
||||
// do nothing
|
||||
}
|
||||
GUIUtil.updateConfidence(tx, progressIndicatorTooltip, txConfidenceIndicator);
|
||||
if (txConfidenceIndicator.getProgress() != 0) {
|
||||
txConfidenceIndicator.setVisible(true);
|
||||
AnchorPane.setRightAnchor(txConfidenceIndicator, 0.0);
|
||||
}
|
||||
if (txConfidenceIndicator.getProgress() >= 1.0 && txUpdater != null) {
|
||||
xmrWalletService.removeWalletListener(txUpdater); // unregister listener
|
||||
txUpdater = null;
|
||||
}
|
||||
updateConfidence(tx);
|
||||
}
|
||||
|
||||
private void updateConfidence(MoneroTx tx) {
|
||||
UserThread.execute(() -> {
|
||||
GUIUtil.updateConfidence(tx, progressIndicatorTooltip, txConfidenceIndicator);
|
||||
if (txConfidenceIndicator.getProgress() != 0) {
|
||||
AnchorPane.setRightAnchor(txConfidenceIndicator, 0.0);
|
||||
}
|
||||
if (txConfidenceIndicator.getProgress() >= 1.0 && txUpdater != null) {
|
||||
xmrWalletService.removeWalletListener(txUpdater); // unregister listener
|
||||
txUpdater = null;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,6 +42,7 @@
|
|||
|
||||
package haveno.desktop.components.indicator;
|
||||
|
||||
import haveno.common.UserThread;
|
||||
import haveno.desktop.components.indicator.skin.StaticProgressIndicatorSkin;
|
||||
import javafx.beans.property.DoubleProperty;
|
||||
import javafx.beans.property.DoublePropertyBase;
|
||||
|
@ -220,7 +221,7 @@ public class TxConfidenceIndicator extends Control {
|
|||
*/
|
||||
|
||||
public final void setProgress(double value) {
|
||||
progressProperty().set(value);
|
||||
UserThread.execute(() -> progressProperty().set(value));
|
||||
}
|
||||
|
||||
public final DoubleProperty progressProperty() {
|
||||
|
|
|
@ -373,44 +373,52 @@ public class OfferBookChartView extends ActivatableViewAndModel<VBox, OfferBookC
|
|||
}
|
||||
|
||||
private List<Double> minMaxFilterLeft(List<XYChart.Data<Number, Number>> data) {
|
||||
double maxValue = data.stream()
|
||||
.mapToDouble(o -> o.getXValue().doubleValue())
|
||||
.max()
|
||||
.orElse(Double.MIN_VALUE);
|
||||
// Hide offers less than a div-factor of dataLimitFactor lower than the highest offer.
|
||||
double minValue = data.stream()
|
||||
.mapToDouble(o -> o.getXValue().doubleValue())
|
||||
.filter(o -> o > maxValue / dataLimitFactor)
|
||||
.min()
|
||||
.orElse(Double.MAX_VALUE);
|
||||
return List.of(minValue, maxValue);
|
||||
synchronized (data) {
|
||||
double maxValue = data.stream()
|
||||
.mapToDouble(o -> o.getXValue().doubleValue())
|
||||
.max()
|
||||
.orElse(Double.MIN_VALUE);
|
||||
// Hide offers less than a div-factor of dataLimitFactor lower than the highest offer.
|
||||
double minValue = data.stream()
|
||||
.mapToDouble(o -> o.getXValue().doubleValue())
|
||||
.filter(o -> o > maxValue / dataLimitFactor)
|
||||
.min()
|
||||
.orElse(Double.MAX_VALUE);
|
||||
return List.of(minValue, maxValue);
|
||||
}
|
||||
}
|
||||
|
||||
private List<Double> minMaxFilterRight(List<XYChart.Data<Number, Number>> data) {
|
||||
double minValue = data.stream()
|
||||
.mapToDouble(o -> o.getXValue().doubleValue())
|
||||
.min()
|
||||
.orElse(Double.MAX_VALUE);
|
||||
synchronized (data) {
|
||||
double minValue = data.stream()
|
||||
.mapToDouble(o -> o.getXValue().doubleValue())
|
||||
.min()
|
||||
.orElse(Double.MAX_VALUE);
|
||||
|
||||
// Hide offers a dataLimitFactor factor higher than the lowest offer
|
||||
double maxValue = data.stream()
|
||||
.mapToDouble(o -> o.getXValue().doubleValue())
|
||||
.filter(o -> o < minValue * dataLimitFactor)
|
||||
.max()
|
||||
.orElse(Double.MIN_VALUE);
|
||||
return List.of(minValue, maxValue);
|
||||
// Hide offers a dataLimitFactor factor higher than the lowest offer
|
||||
double maxValue = data.stream()
|
||||
.mapToDouble(o -> o.getXValue().doubleValue())
|
||||
.filter(o -> o < minValue * dataLimitFactor)
|
||||
.max()
|
||||
.orElse(Double.MIN_VALUE);
|
||||
return List.of(minValue, maxValue);
|
||||
}
|
||||
}
|
||||
|
||||
private List<XYChart.Data<Number, Number>> filterLeft(List<XYChart.Data<Number, Number>> data, double maxValue) {
|
||||
return data.stream()
|
||||
.filter(o -> o.getXValue().doubleValue() > maxValue / dataLimitFactor)
|
||||
.collect(Collectors.toList());
|
||||
synchronized (data) {
|
||||
return data.stream()
|
||||
.filter(o -> o.getXValue().doubleValue() > maxValue / dataLimitFactor)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
|
||||
private List<XYChart.Data<Number, Number>> filterRight(List<XYChart.Data<Number, Number>> data, double minValue) {
|
||||
return data.stream()
|
||||
.filter(o -> o.getXValue().doubleValue() < minValue * dataLimitFactor)
|
||||
.collect(Collectors.toList());
|
||||
synchronized (data) {
|
||||
return data.stream()
|
||||
.filter(o -> o.getXValue().doubleValue() < minValue * dataLimitFactor)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
|
||||
private Tuple4<TableView<OfferListItem>, VBox, Button, Label> getOfferTable(OfferDirection direction) {
|
||||
|
|
|
@ -389,24 +389,26 @@ class OfferBookChartViewModel extends ActivatableViewModel {
|
|||
OfferDirection direction,
|
||||
List<XYChart.Data<Number, Number>> data,
|
||||
ObservableList<OfferListItem> offerTableList) {
|
||||
data.clear();
|
||||
double accumulatedAmount = 0;
|
||||
List<OfferListItem> offerTableListTemp = new ArrayList<>();
|
||||
for (Offer offer : sortedList) {
|
||||
Price price = offer.getPrice();
|
||||
if (price != null) {
|
||||
double amount = (double) offer.getAmount().longValueExact() / LongMath.pow(10, HavenoUtils.XMR_SMALLEST_UNIT_EXPONENT);
|
||||
accumulatedAmount += amount;
|
||||
offerTableListTemp.add(new OfferListItem(offer, accumulatedAmount));
|
||||
|
||||
double priceAsDouble = (double) price.getValue() / LongMath.pow(10, price.smallestUnitExponent());
|
||||
if (direction.equals(OfferDirection.BUY))
|
||||
data.add(0, new XYChart.Data<>(priceAsDouble, accumulatedAmount));
|
||||
else
|
||||
data.add(new XYChart.Data<>(priceAsDouble, accumulatedAmount));
|
||||
synchronized (data) {
|
||||
data.clear();
|
||||
double accumulatedAmount = 0;
|
||||
List<OfferListItem> offerTableListTemp = new ArrayList<>();
|
||||
for (Offer offer : sortedList) {
|
||||
Price price = offer.getPrice();
|
||||
if (price != null) {
|
||||
double amount = (double) offer.getAmount().longValueExact() / LongMath.pow(10, HavenoUtils.XMR_SMALLEST_UNIT_EXPONENT);
|
||||
accumulatedAmount += amount;
|
||||
offerTableListTemp.add(new OfferListItem(offer, accumulatedAmount));
|
||||
|
||||
double priceAsDouble = (double) price.getValue() / LongMath.pow(10, price.smallestUnitExponent());
|
||||
if (direction.equals(OfferDirection.BUY))
|
||||
data.add(0, new XYChart.Data<>(priceAsDouble, accumulatedAmount));
|
||||
else
|
||||
data.add(new XYChart.Data<>(priceAsDouble, accumulatedAmount));
|
||||
}
|
||||
}
|
||||
offerTableList.setAll(offerTableListTemp);
|
||||
}
|
||||
offerTableList.setAll(offerTableListTemp);
|
||||
}
|
||||
|
||||
private boolean isEditEntry(String id) {
|
||||
|
|
|
@ -66,6 +66,8 @@ import org.slf4j.LoggerFactory;
|
|||
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
@ -111,6 +113,8 @@ 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);
|
||||
|
@ -166,16 +170,25 @@ 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().getTxsWithCache(txIds)).start();
|
||||
}
|
||||
|
||||
public void activate() {
|
||||
if (selfTxIdTextField != null) {
|
||||
if (selfTxIdSubscription != null)
|
||||
selfTxIdSubscription.unsubscribe();
|
||||
|
||||
selfTxIdSubscription = EasyBind.subscribe(model.dataModel.isMaker() ? model.dataModel.makerTxId : model.dataModel.takerTxId, id -> {
|
||||
if (!id.isEmpty())
|
||||
if (!id.isEmpty()) {
|
||||
startCachingTxs();
|
||||
selfTxIdTextField.setup(id);
|
||||
else
|
||||
} else {
|
||||
selfTxIdTextField.cleanup();
|
||||
}
|
||||
});
|
||||
}
|
||||
if (peerTxIdTextField != null) {
|
||||
|
@ -183,10 +196,12 @@ public abstract class TradeStepView extends AnchorPane {
|
|||
peerTxIdSubscription.unsubscribe();
|
||||
|
||||
peerTxIdSubscription = EasyBind.subscribe(model.dataModel.isMaker() ? model.dataModel.takerTxId : model.dataModel.makerTxId, id -> {
|
||||
if (!id.isEmpty())
|
||||
if (!id.isEmpty()) {
|
||||
startCachingTxs();
|
||||
peerTxIdTextField.setup(id);
|
||||
else
|
||||
} else {
|
||||
peerTxIdTextField.cleanup();
|
||||
}
|
||||
});
|
||||
}
|
||||
trade.errorMessageProperty().addListener(errorMessageListener);
|
||||
|
|
|
@ -223,7 +223,7 @@ public class BuyerStep2View extends TradeStepView {
|
|||
addTradeInfoBlock();
|
||||
|
||||
PaymentAccountPayload paymentAccountPayload = model.dataModel.getSellersPaymentAccountPayload();
|
||||
String paymentMethodId = paymentAccountPayload != null ? paymentAccountPayload.getPaymentMethodId() : "";
|
||||
String paymentMethodId = paymentAccountPayload != null ? paymentAccountPayload.getPaymentMethodId() : "<missing payment account payload>";
|
||||
TitledGroupBg accountTitledGroupBg = addTitledGroupBg(gridPane, ++gridRow, 4,
|
||||
Res.get("portfolio.pending.step2_buyer.startPaymentUsing", Res.get(paymentMethodId)),
|
||||
Layout.COMPACT_GROUP_DISTANCE);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue