mirror of
https://github.com/bisq-network/bisq.git
synced 2024-11-19 09:52:23 +01:00
Add new tx-by-id cache to speed up BsqWalletService.isWalletTransaction
Reduce a hotspot searching the BSQ wallet for the user's votes, upon selecting a list item of the Vote Result view, by optimising the method 'BsqWalletService.isWalletTransaction(String)'. Do this by adding a lazily initialised Map field, 'walletTransactionsById', kept in sync with the existing 'walletTransactions' List field, similar to the tx-by- id cache removed from the base class in the previous commit, so that a linear scan of that list can be avoided. Don't bother to make the cache thread safe, however, since 'isWalletTransaction' is only called from the user thread and wasn't thread safe to begin with -- access to 'walletTransactions' isn't synchronised, and it is updated only on the user thread, after a 100 ms delay upon any changes to the BSQ wallet. Also remove the unused methods 'getUnverifiedBsqTransactions()' and 'getBsqWalletTransactions()' from the class.
This commit is contained in:
parent
d803a67d0d
commit
3a70213d1b
@ -48,7 +48,6 @@ import org.bitcoinj.core.InsufficientMoneyException;
|
|||||||
import org.bitcoinj.core.NetworkParameters;
|
import org.bitcoinj.core.NetworkParameters;
|
||||||
import org.bitcoinj.core.Sha256Hash;
|
import org.bitcoinj.core.Sha256Hash;
|
||||||
import org.bitcoinj.core.Transaction;
|
import org.bitcoinj.core.Transaction;
|
||||||
import org.bitcoinj.core.TransactionConfidence;
|
|
||||||
import org.bitcoinj.core.TransactionInput;
|
import org.bitcoinj.core.TransactionInput;
|
||||||
import org.bitcoinj.core.TransactionOutPoint;
|
import org.bitcoinj.core.TransactionOutPoint;
|
||||||
import org.bitcoinj.core.TransactionOutput;
|
import org.bitcoinj.core.TransactionOutput;
|
||||||
@ -60,14 +59,12 @@ import org.bitcoinj.wallet.SendRequest;
|
|||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
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.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.function.Function;
|
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
@ -95,6 +92,7 @@ public class BsqWalletService extends WalletService implements DaoStateListener
|
|||||||
private final DaoStateService daoStateService;
|
private final DaoStateService daoStateService;
|
||||||
private final UnconfirmedBsqChangeOutputListService unconfirmedBsqChangeOutputListService;
|
private final UnconfirmedBsqChangeOutputListService unconfirmedBsqChangeOutputListService;
|
||||||
private final List<Transaction> walletTransactions = new ArrayList<>();
|
private final List<Transaction> walletTransactions = new ArrayList<>();
|
||||||
|
private Map<String, Transaction> walletTransactionsById;
|
||||||
private final CopyOnWriteArraySet<BsqBalanceListener> bsqBalanceListeners = new CopyOnWriteArraySet<>();
|
private final CopyOnWriteArraySet<BsqBalanceListener> bsqBalanceListeners = new CopyOnWriteArraySet<>();
|
||||||
private final List<WalletTransactionsChangeListener> walletTransactionsChangeListeners = new ArrayList<>();
|
private final List<WalletTransactionsChangeListener> walletTransactionsChangeListeners = new ArrayList<>();
|
||||||
private boolean updateBsqWalletTransactionsPending;
|
private boolean updateBsqWalletTransactionsPending;
|
||||||
@ -233,7 +231,7 @@ public class BsqWalletService extends WalletService implements DaoStateListener
|
|||||||
private void updateBsqBalance() {
|
private void updateBsqBalance() {
|
||||||
long ts = System.currentTimeMillis();
|
long ts = System.currentTimeMillis();
|
||||||
unverifiedBalance = Coin.valueOf(
|
unverifiedBalance = Coin.valueOf(
|
||||||
getTransactions(false).stream()
|
walletTransactions.stream()
|
||||||
.filter(tx -> tx.getConfidence().getConfidenceType() == PENDING)
|
.filter(tx -> tx.getConfidence().getConfidenceType() == PENDING)
|
||||||
.mapToLong(tx -> {
|
.mapToLong(tx -> {
|
||||||
// Sum up outputs into BSQ wallet and subtract the inputs using lockup or unlocking
|
// Sum up outputs into BSQ wallet and subtract the inputs using lockup or unlocking
|
||||||
@ -270,7 +268,7 @@ public class BsqWalletService extends WalletService implements DaoStateListener
|
|||||||
.sum()
|
.sum()
|
||||||
);
|
);
|
||||||
|
|
||||||
Set<String> confirmedTxIdSet = getTransactions(false).stream()
|
Set<String> confirmedTxIdSet = walletTransactions.stream()
|
||||||
.filter(tx -> tx.getConfidence().getConfidenceType() == BUILDING)
|
.filter(tx -> tx.getConfidence().getConfidenceType() == BUILDING)
|
||||||
.map(Transaction::getTxId)
|
.map(Transaction::getTxId)
|
||||||
.map(Sha256Hash::toString)
|
.map(Sha256Hash::toString)
|
||||||
@ -343,13 +341,15 @@ public class BsqWalletService extends WalletService implements DaoStateListener
|
|||||||
// BSQ TransactionOutputs and Transactions
|
// BSQ TransactionOutputs and Transactions
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// not thread safe - call only from user thread
|
||||||
public List<Transaction> getClonedWalletTransactions() {
|
public List<Transaction> getClonedWalletTransactions() {
|
||||||
return new ArrayList<>(walletTransactions);
|
return new ArrayList<>(walletTransactions);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// not thread safe - call only from user thread
|
||||||
public Stream<Transaction> getPendingWalletTransactionsStream() {
|
public Stream<Transaction> getPendingWalletTransactionsStream() {
|
||||||
return walletTransactions.stream()
|
return walletTransactions.stream()
|
||||||
.filter(transaction -> transaction.getConfidence().getConfidenceType() == TransactionConfidence.ConfidenceType.PENDING);
|
.filter(transaction -> transaction.getConfidence().getConfidenceType() == PENDING);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateBsqWalletTransactions() {
|
private void updateBsqWalletTransactions() {
|
||||||
@ -363,6 +363,7 @@ public class BsqWalletService extends WalletService implements DaoStateListener
|
|||||||
UserThread.runAfter(() -> {
|
UserThread.runAfter(() -> {
|
||||||
walletTransactions.clear();
|
walletTransactions.clear();
|
||||||
walletTransactions.addAll(getTransactions(false));
|
walletTransactions.addAll(getTransactions(false));
|
||||||
|
walletTransactionsById = null;
|
||||||
walletTransactionsChangeListeners.forEach(WalletTransactionsChangeListener::onWalletTransactionsChange);
|
walletTransactionsChangeListeners.forEach(WalletTransactionsChangeListener::onWalletTransactionsChange);
|
||||||
updateBsqBalance();
|
updateBsqBalance();
|
||||||
updateBsqWalletTransactionsPending = false;
|
updateBsqWalletTransactionsPending = false;
|
||||||
@ -371,37 +372,6 @@ public class BsqWalletService extends WalletService implements DaoStateListener
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Set<Transaction> getBsqWalletTransactions() {
|
|
||||||
return getTransactions(false).stream()
|
|
||||||
.filter(transaction -> transaction.getConfidence().getConfidenceType() == PENDING ||
|
|
||||||
daoStateService.containsTx(transaction.getTxId().toString()))
|
|
||||||
.collect(Collectors.toSet());
|
|
||||||
}
|
|
||||||
|
|
||||||
public Set<Transaction> getUnverifiedBsqTransactions() {
|
|
||||||
Set<Transaction> bsqWalletTransactions = getBsqWalletTransactions();
|
|
||||||
Set<Transaction> walletTxs = new HashSet<>(getTransactions(false));
|
|
||||||
checkArgument(walletTxs.size() >= bsqWalletTransactions.size(),
|
|
||||||
"We cannot have more txsWithOutputsFoundInBsqTxo than walletTxs");
|
|
||||||
if (walletTxs.size() == bsqWalletTransactions.size()) {
|
|
||||||
// As expected
|
|
||||||
return new HashSet<>();
|
|
||||||
} else {
|
|
||||||
Map<String, Transaction> map = walletTxs.stream()
|
|
||||||
.collect(Collectors.toMap(t -> t.getTxId().toString(), Function.identity()));
|
|
||||||
|
|
||||||
Set<String> walletTxIds = walletTxs.stream()
|
|
||||||
.map(Transaction::getTxId).map(Sha256Hash::toString).collect(Collectors.toSet());
|
|
||||||
Set<String> bsqTxIds = bsqWalletTransactions.stream()
|
|
||||||
.map(Transaction::getTxId).map(Sha256Hash::toString).collect(Collectors.toSet());
|
|
||||||
|
|
||||||
walletTxIds.stream()
|
|
||||||
.filter(bsqTxIds::contains)
|
|
||||||
.forEach(map::remove);
|
|
||||||
return new HashSet<>(map.values());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Coin getValueSentFromMeForTransaction(Transaction transaction) throws ScriptException {
|
public Coin getValueSentFromMeForTransaction(Transaction transaction) throws ScriptException {
|
||||||
Coin result = Coin.ZERO;
|
Coin result = Coin.ZERO;
|
||||||
@ -414,7 +384,7 @@ public class BsqWalletService extends WalletService implements DaoStateListener
|
|||||||
// We grab the parent tx of the connected output
|
// We grab the parent tx of the connected output
|
||||||
final Transaction parentTransaction = connectedOutput.getParentTransaction();
|
final Transaction parentTransaction = connectedOutput.getParentTransaction();
|
||||||
final boolean isConfirmed = parentTransaction != null &&
|
final boolean isConfirmed = parentTransaction != null &&
|
||||||
parentTransaction.getConfidence().getConfidenceType() == TransactionConfidence.ConfidenceType.BUILDING;
|
parentTransaction.getConfidence().getConfidenceType() == BUILDING;
|
||||||
if (connectedOutput.isMineOrWatched(wallet)) {
|
if (connectedOutput.isMineOrWatched(wallet)) {
|
||||||
if (isConfirmed) {
|
if (isConfirmed) {
|
||||||
// We lookup if we have a BSQ tx matching the parent tx
|
// We lookup if we have a BSQ tx matching the parent tx
|
||||||
@ -455,7 +425,7 @@ public class BsqWalletService extends WalletService implements DaoStateListener
|
|||||||
for (int i = 0; i < transaction.getOutputs().size(); i++) {
|
for (int i = 0; i < transaction.getOutputs().size(); i++) {
|
||||||
TransactionOutput output = transaction.getOutputs().get(i);
|
TransactionOutput output = transaction.getOutputs().get(i);
|
||||||
final boolean isConfirmed = output.getParentTransaction() != null &&
|
final boolean isConfirmed = output.getParentTransaction() != null &&
|
||||||
output.getParentTransaction().getConfidence().getConfidenceType() == TransactionConfidence.ConfidenceType.BUILDING;
|
output.getParentTransaction().getConfidence().getConfidenceType() == BUILDING;
|
||||||
if (output.isMineOrWatched(wallet)) {
|
if (output.isMineOrWatched(wallet)) {
|
||||||
if (isConfirmed) {
|
if (isConfirmed) {
|
||||||
if (txOptional.isPresent()) {
|
if (txOptional.isPresent()) {
|
||||||
@ -484,8 +454,13 @@ public class BsqWalletService extends WalletService implements DaoStateListener
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// not thread safe - call only from user thread
|
||||||
public Optional<Transaction> isWalletTransaction(String txId) {
|
public Optional<Transaction> isWalletTransaction(String txId) {
|
||||||
return walletTransactions.stream().filter(e -> e.getTxId().toString().equals(txId)).findAny();
|
if (walletTransactionsById == null) {
|
||||||
|
walletTransactionsById = walletTransactions.stream()
|
||||||
|
.collect(Collectors.toMap(tx -> tx.getTxId().toString(), tx -> tx));
|
||||||
|
}
|
||||||
|
return Optional.ofNullable(walletTransactionsById.get(txId));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user