Cache transaction list for 2 minutes, and synchronize, to prevent the balance and transactions APIs both requesting at once.

This ensures that only a single round of requests (per coin) is used for the wallettransactions and balance APIs. It also speeds up loading on subsequent requests. The 2 minute cache isn't much longer than the foreign block times, so shouldn't cause values to be too out of date.
This commit is contained in:
CalDescent 2022-02-03 21:04:49 +00:00
parent 892612c084
commit 9224ffbf73

View File

@ -39,6 +39,7 @@ import org.qortal.utils.Amounts;
import org.qortal.utils.BitTwiddling;
import com.google.common.hash.HashCode;
import org.qortal.utils.NTP;
/** Bitcoin-like (Bitcoin, Litecoin, etc.) support */
public abstract class Bitcoiny implements ForeignBlockchain {
@ -53,6 +54,11 @@ public abstract class Bitcoiny implements ForeignBlockchain {
protected final NetworkParameters params;
/** Cache recent transactions to speed up subsequent lookups */
protected List<SimpleTransaction> transactionsCache;
protected Long transactionsCacheTimestamp;
protected static long TRANSACTIONS_CACHE_TIMEOUT = 2 * 60 * 1000L; // 2 minutes
/** Keys that have been previously marked as fully spent,<br>
* i.e. keys with transactions but with no unspent outputs. */
protected final Set<ECKey> spentKeys = Collections.synchronizedSet(new HashSet<>());
@ -353,6 +359,18 @@ public abstract class Bitcoiny implements ForeignBlockchain {
}
public List<SimpleTransaction> getWalletTransactions(String key58) throws ForeignBlockchainException {
synchronized (this) {
// Serve from the cache if it's recent
if (transactionsCache != null && transactionsCacheTimestamp != null) {
Long now = NTP.getTime();
boolean isCacheStale = (now != null && now - transactionsCacheTimestamp >= TRANSACTIONS_CACHE_TIMEOUT);
if (!isCacheStale) {
LOGGER.info("Serving transactions from cache");
return transactionsCache;
}
}
LOGGER.info("Fetching transactions from ElectrumX");
Context.propagate(bitcoinjContext);
Wallet wallet = walletFromDeterministicKey58(key58);
@ -401,8 +419,7 @@ public abstract class Bitcoiny implements ForeignBlockchain {
}
// We haven't hit our search limit yet so increment the counter and keep looking
unusedCounter++;
}
else {
} else {
// Some keys in this batch were used, so reset the counter
unusedCounter = 0;
}
@ -415,7 +432,14 @@ public abstract class Bitcoiny implements ForeignBlockchain {
Comparator<SimpleTransaction> newestTimestampFirstComparator = Comparator.comparingInt(SimpleTransaction::getTimestamp).reversed();
return walletTransactions.stream().map(t -> convertToSimpleTransaction(t, keySet)).sorted(newestTimestampFirstComparator).collect(Collectors.toList());
// Update cache and return
transactionsCacheTimestamp = NTP.getTime();
transactionsCache = walletTransactions.stream()
.map(t -> convertToSimpleTransaction(t, keySet))
.sorted(newestTimestampFirstComparator).collect(Collectors.toList());
return transactionsCache;
}
}
protected SimpleTransaction convertToSimpleTransaction(BitcoinyTransaction t, Set<String> keySet) {