mirror of
https://github.com/haveno-dex/haveno.git
synced 2024-12-23 03:59:36 +00:00
improve performance by pre-fetching txs for subaddress queries
This commit is contained in:
parent
4fb62d8669
commit
d9f2ce425f
3 changed files with 33 additions and 27 deletions
|
@ -37,9 +37,6 @@ import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.CopyOnWriteArraySet;
|
import java.util.concurrent.CopyOnWriteArraySet;
|
||||||
import java.util.concurrent.ExecutorService;
|
|
||||||
import java.util.concurrent.Executors;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
@ -57,6 +54,7 @@ import monero.wallet.MoneroWallet;
|
||||||
import monero.wallet.MoneroWalletRpc;
|
import monero.wallet.MoneroWalletRpc;
|
||||||
import monero.wallet.model.MoneroCheckTx;
|
import monero.wallet.model.MoneroCheckTx;
|
||||||
import monero.wallet.model.MoneroDestination;
|
import monero.wallet.model.MoneroDestination;
|
||||||
|
import monero.wallet.model.MoneroOutputQuery;
|
||||||
import monero.wallet.model.MoneroOutputWallet;
|
import monero.wallet.model.MoneroOutputWallet;
|
||||||
import monero.wallet.model.MoneroSubaddress;
|
import monero.wallet.model.MoneroSubaddress;
|
||||||
import monero.wallet.model.MoneroTransferQuery;
|
import monero.wallet.model.MoneroTransferQuery;
|
||||||
|
@ -784,8 +782,9 @@ public class XmrWalletService {
|
||||||
return addressEntry.get();
|
return addressEntry.get();
|
||||||
} else {
|
} else {
|
||||||
// We try to use available and not yet used entries
|
// We try to use available and not yet used entries
|
||||||
|
List<MoneroTxWallet> incomingTxs = getIncomingTxs(null); // pre-fetch all incoming txs to avoid query per subaddress
|
||||||
Optional<XmrAddressEntry> emptyAvailableAddressEntry = getAddressEntryListAsImmutableList().stream().filter(e -> XmrAddressEntry.Context.AVAILABLE == e.getContext())
|
Optional<XmrAddressEntry> emptyAvailableAddressEntry = getAddressEntryListAsImmutableList().stream().filter(e -> XmrAddressEntry.Context.AVAILABLE == e.getContext())
|
||||||
.filter(e -> isSubaddressUnused(e.getSubaddressIndex())).findAny();
|
.filter(e -> isSubaddressUnused(e.getSubaddressIndex(), incomingTxs)).findAny();
|
||||||
if (emptyAvailableAddressEntry.isPresent()) {
|
if (emptyAvailableAddressEntry.isPresent()) {
|
||||||
return xmrAddressEntryList.swapAvailableToAddressEntryWithOfferId(emptyAvailableAddressEntry.get(), context, offerId);
|
return xmrAddressEntryList.swapAvailableToAddressEntryWithOfferId(emptyAvailableAddressEntry.get(), context, offerId);
|
||||||
} else {
|
} else {
|
||||||
|
@ -890,7 +889,33 @@ public class XmrWalletService {
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isSubaddressUnused(int subaddressIndex) {
|
public boolean isSubaddressUnused(int subaddressIndex) {
|
||||||
return getNumTxOutputsForSubaddress(subaddressIndex) == 0;
|
return isSubaddressUnused(subaddressIndex, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isSubaddressUnused(int subaddressIndex, List<MoneroTxWallet> incomingTxs) {
|
||||||
|
return getNumTxOutputsForSubaddress(subaddressIndex, incomingTxs) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getNumTxOutputsForSubaddress(int subaddressIndex) {
|
||||||
|
return getNumTxOutputsForSubaddress(subaddressIndex, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getNumTxOutputsForSubaddress(int subaddressIndex, List<MoneroTxWallet> incomingTxs) {
|
||||||
|
if (incomingTxs == null) incomingTxs = getIncomingTxs(subaddressIndex);
|
||||||
|
int numUnspentOutputs = 0;
|
||||||
|
for (MoneroTxWallet tx : incomingTxs) {
|
||||||
|
numUnspentOutputs += tx.isConfirmed() ? tx.getOutputsWallet(new MoneroOutputQuery().setSubaddressIndex(subaddressIndex)).size() : 1; // TODO: monero-project does not provide outputs for unconfirmed txs
|
||||||
|
}
|
||||||
|
return numUnspentOutputs;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<MoneroTxWallet> getIncomingTxs(Integer subaddressIndex) {
|
||||||
|
return wallet.getTxs(new MoneroTxQuery()
|
||||||
|
.setTransferQuery((new MoneroTransferQuery()
|
||||||
|
.setAccountIndex(0)
|
||||||
|
.setSubaddressIndex(subaddressIndex)
|
||||||
|
.setIsIncoming(true)))
|
||||||
|
.setIncludeOutputs(true));
|
||||||
}
|
}
|
||||||
|
|
||||||
public Coin getBalanceForAddress(String address) {
|
public Coin getBalanceForAddress(String address) {
|
||||||
|
@ -917,24 +942,6 @@ public class XmrWalletService {
|
||||||
return Coin.valueOf(balance.longValueExact());
|
return Coin.valueOf(balance.longValueExact());
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getNumTxOutputsForSubaddress(int subaddressIndex) {
|
|
||||||
|
|
||||||
// get txs with transfers to the subaddress
|
|
||||||
List<MoneroTxWallet> txs = wallet.getTxs(new MoneroTxQuery()
|
|
||||||
.setTransferQuery((new MoneroTransferQuery()
|
|
||||||
.setAccountIndex(0)
|
|
||||||
.setSubaddressIndex(subaddressIndex)
|
|
||||||
.setIsIncoming(true)))
|
|
||||||
.setIncludeOutputs(true));
|
|
||||||
|
|
||||||
// count num outputs
|
|
||||||
int numUnspentOutputs = 0;
|
|
||||||
for (MoneroTxWallet tx : txs) {
|
|
||||||
numUnspentOutputs += tx.isConfirmed() ? tx.getOutputs().size() : 1; // TODO: monero-project does not provide outputs for unconfirmed txs
|
|
||||||
}
|
|
||||||
return numUnspentOutputs;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Coin getAvailableConfirmedBalance() {
|
public Coin getAvailableConfirmedBalance() {
|
||||||
return wallet != null ? Coin.valueOf(wallet.getUnlockedBalance(0).longValueExact()) : Coin.ZERO;
|
return wallet != null ? Coin.valueOf(wallet.getUnlockedBalance(0).longValueExact()) : Coin.ZERO;
|
||||||
}
|
}
|
||||||
|
|
|
@ -90,7 +90,7 @@ public class ArbitratorProtocol extends DisputeProtocol {
|
||||||
ArbitratorProcessDepositRequest.class)
|
ArbitratorProcessDepositRequest.class)
|
||||||
.using(new TradeTaskRunner(trade,
|
.using(new TradeTaskRunner(trade,
|
||||||
() -> {
|
() -> {
|
||||||
if (trade.getState() == Trade.State.ARBITRATOR_PUBLISHED_DEPOSIT_TXS) {
|
if (trade.getState().ordinal() >= Trade.State.ARBITRATOR_PUBLISHED_DEPOSIT_TXS.ordinal()) {
|
||||||
stopTimeout();
|
stopTimeout();
|
||||||
this.errorMessageHandler = null;
|
this.errorMessageHandler = null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -424,7 +424,6 @@ public abstract class TradeProtocol implements DecryptedDirectMessageListener, D
|
||||||
handleTaskRunnerSuccess(peer, message);
|
handleTaskRunnerSuccess(peer, message);
|
||||||
},
|
},
|
||||||
(errorMessage) -> {
|
(errorMessage) -> {
|
||||||
stopTimeout();
|
|
||||||
handleTaskRunnerFault(peer, message, errorMessage);
|
handleTaskRunnerFault(peer, message, errorMessage);
|
||||||
})))
|
})))
|
||||||
.executeTasks(true);
|
.executeTasks(true);
|
||||||
|
@ -589,14 +588,14 @@ public abstract class TradeProtocol implements DecryptedDirectMessageListener, D
|
||||||
// Timeout
|
// Timeout
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
protected void startTimeout(long timeoutSec) {
|
protected synchronized void startTimeout(long timeoutSec) {
|
||||||
stopTimeout();
|
stopTimeout();
|
||||||
timeoutTimer = UserThread.runAfter(() -> {
|
timeoutTimer = UserThread.runAfter(() -> {
|
||||||
handleError("Timeout reached. Protocol did not complete in " + timeoutSec + " sec. TradeID=" + trade.getId() + ", state=" + trade.stateProperty().get());
|
handleError("Timeout reached. Protocol did not complete in " + timeoutSec + " sec. TradeID=" + trade.getId() + ", state=" + trade.stateProperty().get());
|
||||||
}, timeoutSec);
|
}, timeoutSec);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void stopTimeout() {
|
protected synchronized void stopTimeout() {
|
||||||
if (timeoutTimer != null) {
|
if (timeoutTimer != null) {
|
||||||
timeoutTimer.stop();
|
timeoutTimer.stop();
|
||||||
timeoutTimer = null;
|
timeoutTimer = null;
|
||||||
|
|
Loading…
Reference in a new issue