improve stability on tor, refactor startup and shut down

refactor startup sequence to improve message reliability
refactor shut down sequence to finish processing messages
reduce monerod requests to improve slow tor connections
refactor trade wallet polling
monero node service uses default data directory unless local
connections service checks connection by polling daemon
connections service supports getRefreshPeriodMs and shutting down
add make config: monerod-stagenet-custom
fix bugs in key image polling
force stop wallet on deletion
trade manager initializes persisted trades on data received
support hardcoding monero log level and request stack traces
remove xmrAddress from Arbitrator model
fix formatting of MoneroWalletRpcManager
This commit is contained in:
woodser 2023-04-17 08:54:10 -04:00
parent 5e364f7e7e
commit 2afa5d761d
51 changed files with 1058 additions and 644 deletions

View file

@ -45,7 +45,6 @@ public class ArbitratorRegistrationViewModel extends AgentRegistrationViewModel<
String emailAddress) {
return new Arbitrator(
p2PService.getAddress(),
xmrWalletService.getWallet().getPrimaryAddress(), // TODO: how is arbitrator address used?
keyRing.getPubKeyRing(),
new ArrayList<>(languageCodes),
new Date().getTime(),

View file

@ -19,6 +19,8 @@ package haveno.desktop.main.funds.deposit;
import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;
import common.types.Filter;
import haveno.core.locale.Res;
import haveno.core.trade.HavenoUtils;
import haveno.core.util.coin.CoinFormatter;
@ -85,7 +87,7 @@ class DepositListItem {
tooltip = new Tooltip(Res.get("shared.notUsedYet"));
txConfidenceIndicator.setProgress(0);
txConfidenceIndicator.setTooltip(tooltip);
MoneroTx tx = getTxWithFewestConfirmations();
MoneroTx tx = getTxWithFewestConfirmations(cachedTxs);
if (tx == null) {
txConfidenceIndicator.setVisible(false);
} else {
@ -132,20 +134,20 @@ class DepositListItem {
return numTxOutputs;
}
public long getNumConfirmationsSinceFirstUsed() {
MoneroTx tx = getTxWithFewestConfirmations();
public long getNumConfirmationsSinceFirstUsed(List<MoneroTxWallet> incomingTxs) {
MoneroTx tx = getTxWithFewestConfirmations(incomingTxs);
return tx == null ? 0 : tx.getNumConfirmations();
}
private MoneroTxWallet getTxWithFewestConfirmations() {
private MoneroTxWallet getTxWithFewestConfirmations(List<MoneroTxWallet> incomingTxs) {
// get txs with incoming transfers to subaddress
List<MoneroTxWallet> txs = xmrWalletService.getWallet()
.getTxs(new MoneroTxQuery()
.setTransferQuery(new MoneroTransferQuery()
.setIsIncoming(true)
.setSubaddressIndex(addressEntry.getSubaddressIndex())));
MoneroTxQuery query = new MoneroTxQuery()
.setTransferQuery(new MoneroTransferQuery()
.setIsIncoming(true)
.setSubaddressIndex(addressEntry.getSubaddressIndex()));
List<MoneroTxWallet> txs = incomingTxs == null ? xmrWalletService.getWallet().getTxs(query) : Filter.apply(query, incomingTxs);
// get tx with fewest confirmations
MoneroTxWallet highestTx = null;
for (MoneroTxWallet tx : txs) if (highestTx == null || tx.getNumConfirmations() < highestTx.getNumConfirmations()) highestTx = tx;

View file

@ -147,9 +147,12 @@ public class DepositView extends ActivatableView<VBox, Void> {
setUsageColumnCellFactory();
setConfidenceColumnCellFactory();
// prefetch all incoming txs to avoid query per subaddress
List<MoneroTxWallet> incomingTxs = xmrWalletService.getIncomingTxs();
addressColumn.setComparator(Comparator.comparing(DepositListItem::getAddressString));
balanceColumn.setComparator(Comparator.comparing(DepositListItem::getBalanceAsBI));
confirmationsColumn.setComparator(Comparator.comparingLong(o -> o.getNumConfirmationsSinceFirstUsed()));
confirmationsColumn.setComparator(Comparator.comparingLong(o -> o.getNumConfirmationsSinceFirstUsed(incomingTxs)));
usageColumn.setComparator(Comparator.comparingInt(DepositListItem::getNumTxOutputs));
tableView.getSortOrder().add(usageColumn);
tableView.setItems(sortedList);

View file

@ -35,7 +35,7 @@ class TransactionAwareOpenOffer implements TransactionAwareTradable {
String txId = transaction.getHash();
return paymentTxId.equals(txId);
return txId.equals(paymentTxId);
}
public Tradable asTradable() {

View file

@ -34,6 +34,7 @@ import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import monero.wallet.model.MoneroIncomingTransfer;
import monero.wallet.model.MoneroOutgoingTransfer;
import monero.wallet.model.MoneroTxQuery;
import monero.wallet.model.MoneroTxWallet;
import monero.wallet.model.MoneroWalletListener;
@ -60,6 +61,8 @@ class TransactionsListItem {
@Getter
private boolean initialTxConfidenceVisibility = true;
private final Supplier<LazyFields> lazyFieldsSupplier;
private XmrWalletService xmrWalletService;
MoneroWalletListener walletListener;
private static class LazyFields {
TxConfidenceIndicator txConfidenceIndicator;
@ -82,6 +85,8 @@ class TransactionsListItem {
TransactionAwareTradable transactionAwareTradable) {
this.memo = tx.getNote();
this.txId = tx.getHash();
this.xmrWalletService = xmrWalletService;
this.confirmations = tx.getNumConfirmations() == null ? 0 : tx.getNumConfirmations();
Optional<Tradable> optionalTradable = Optional.ofNullable(transactionAwareTradable)
.map(TransactionAwareTradable::asTradable);
@ -182,18 +187,24 @@ class TransactionsListItem {
}});
// listen for tx updates
// TODO: this only listens for new blocks, listen for double spend
xmrWalletService.addWalletListener(new MoneroWalletListener() {
walletListener = new MoneroWalletListener() {
@Override
public void onNewBlock(long height) {
MoneroTxWallet tx = xmrWalletService.getWallet().getTx(txId);
MoneroTxWallet tx = xmrWalletService.getWallet().getTxs(new MoneroTxQuery()
.setHash(txId)
.setInTxPool(confirmations > 0 ? false : null)).get(0);
GUIUtil.updateConfidence(tx, lazy().tooltip, lazy().txConfidenceIndicator);
confirmations = tx.getNumConfirmations();
}
});
};
xmrWalletService.addWalletListener(walletListener);
}
public void cleanup() {
if (walletListener != null) {
xmrWalletService.removeWalletListener(walletListener);
walletListener = null;
}
}
public TxConfidenceIndicator getTxConfidenceIndicator() {

View file

@ -67,7 +67,6 @@ import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import lombok.extern.slf4j.Slf4j;
import monero.wallet.model.MoneroTxWallet;
import org.bitcoinj.core.Coin;
import java.math.BigInteger;
import java.util.Date;
@ -727,13 +726,13 @@ public class DisputeSummaryWindow extends Overlay<DisputeSummaryWindow> {
sellerPayoutAmount.equals(sellerSecurityDeposit)) {
buyerGetsTradeAmountRadioButton.setSelected(true);
} else if (buyerPayoutAmount.equals(tradeAmount.add(buyerSecurityDeposit).add(sellerSecurityDeposit)) &&
sellerPayoutAmount.equals(Coin.ZERO)) {
sellerPayoutAmount.equals(BigInteger.valueOf(0))) {
buyerGetsAllRadioButton.setSelected(true);
} else if (sellerPayoutAmount.equals(tradeAmount.add(sellerSecurityDeposit))
&& buyerPayoutAmount.equals(buyerSecurityDeposit)) {
sellerGetsTradeAmountRadioButton.setSelected(true);
} else if (sellerPayoutAmount.equals(tradeAmount.add(buyerSecurityDeposit).add(sellerSecurityDeposit))
&& buyerPayoutAmount.equals(Coin.ZERO)) {
&& buyerPayoutAmount.equals(BigInteger.valueOf(0))) {
sellerGetsAllRadioButton.setSelected(true);
} else {
customRadioButton.setSelected(true);

View file

@ -448,6 +448,8 @@ public class PendingTradesViewModel extends ActivatableWithDataModel<PendingTrad
switch (payoutState) {
case PAYOUT_PUBLISHED:
case PAYOUT_CONFIRMED:
case PAYOUT_UNLOCKED:
sellerState.set(SellerState.STEP4);
buyerState.set(BuyerState.STEP4);
break;

View file

@ -788,6 +788,14 @@ public class PreferencesView extends ActivatableViewAndModel<GridPane, Preferenc
.show();
});
// We use opposite property (useStandbyMode) in preferences to have the default value (false) set as we want it,
// so users who update gets set avoidStandbyMode=true (useStandbyMode=false)
if (displayStandbyModeFeature) {
avoidStandbyMode.setSelected(!preferences.isUseStandbyMode());
avoidStandbyMode.setOnAction(e -> preferences.setUseStandbyMode(!avoidStandbyMode.isSelected()));
} else {
preferences.setUseStandbyMode(false);
}
}
private void activateAutoConfirmPreferences() {