Skip to content

Commit

Permalink
Refactor getFundingAddresses to use memoization
Browse files Browse the repository at this point in the history
Also reordered some import statements according to Bisq style rules.
  • Loading branch information
ghubstan committed Jun 18, 2020
1 parent 9db9ee2 commit b0e278f
Showing 1 changed file with 37 additions and 42 deletions.
79 changes: 37 additions & 42 deletions core/src/main/java/bisq/core/grpc/CoreWalletsService.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,16 @@
import bisq.core.btc.wallet.BtcWalletService;
import bisq.core.btc.wallet.WalletsManager;

import bisq.common.util.Tuple3;

import org.bitcoinj.core.Address;
import org.bitcoinj.core.TransactionConfidence;
import org.bitcoinj.crypto.KeyCrypterScrypt;

import javax.inject.Inject;

import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;

import org.spongycastle.crypto.params.KeyParameter;

import java.text.DecimalFormat;
Expand All @@ -30,10 +32,6 @@

import javax.annotation.Nullable;

import com.google.common.cache.CacheLoader;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.LoadingCache;

import static java.lang.String.format;
import static java.util.concurrent.TimeUnit.SECONDS;

Expand All @@ -56,6 +54,7 @@ class CoreWalletsService {
private final Function<Long, String> formatSatoshis = (sats) ->
btcFormat.format(BigDecimal.valueOf(sats).divide(satoshiDivisor));


@Inject
public CoreWalletsService(Balances balances,
WalletsManager walletsManager,
Expand Down Expand Up @@ -92,19 +91,6 @@ public String getAddressBalanceInfo(String addressString) {
+ ((numConfirmations > 0) ? (" confirmations: " + format("%6d", numConfirmations)) : "");
}

/**
* Memoization stores the results of expensive function calls and returns
* the cached result when the same input occurs again.
*
* Resulting LoadingCache is used by calling `.get(input I)` or
* `.getUnchecked(input I)`, depending on whether or not `f` can return null.
* That's because CacheLoader throws an exception on null output from `f`.
*/
private static <I,O> LoadingCache<I,O> memoize(Function<I,O> f) {
// f::apply is used, because Guava 20.0 Function doesn't yet extend
// Java Function.
return CacheBuilder.newBuilder().build(CacheLoader.from(f::apply));
}

public String getFundingAddresses() {
if (!walletsManager.areWalletsAvailable())
Expand All @@ -117,42 +103,37 @@ public String getFundingAddresses() {
btcWalletService.getFreshAddressEntry();

List<String> addressStrings =
btcWalletService
.getAvailableAddressEntries()
.stream()
.map(addressEntry -> addressEntry.getAddressString())
.collect(Collectors.toList());
btcWalletService
.getAvailableAddressEntries()
.stream()
.map(AddressEntry::getAddressString)
.collect(Collectors.toList());

// getAddressBalance is memoized, because we'll map it over addresses twice.
// To get the balances, we'll be using .getUnchecked, because we know that
// this::getAddressBalance cannot return null.
var balances = memoize(this::getAddressBalance);

boolean noAddressHasZeroBalance =
addressStrings.stream()
.allMatch(addressString -> balances.getUnchecked(addressString) != 0);
addressStrings.stream()
.allMatch(addressString -> balances.getUnchecked(addressString) != 0);

if (noAddressHasZeroBalance) {
var newZeroBalanceAddress = btcWalletService.getFreshAddressEntry();
addressStrings.add(newZeroBalanceAddress.getAddressString());
}

String fundingAddressTable =
addressStrings.stream()
.map(addressString -> {
var balance = balances.getUnchecked(addressString);
var stringFormattedBalance = formatSatoshis.apply(balance);
var numConfirmations =
getNumConfirmationsForMostRecentTransaction(addressString);
String addressInfo =
"" + addressString
+ " balance: " + format("%13s", stringFormattedBalance)
+ ((balance > 0) ? (" confirmations: " + format("%6d", numConfirmations)) : "");
return addressInfo;
})
.collect(Collectors.joining("\n"));

return fundingAddressTable;
return addressStrings.stream()
.map(addressString -> {
var balance = balances.getUnchecked(addressString);
var stringFormattedBalance = formatSatoshis.apply(balance);
var numConfirmations =
getNumConfirmationsForMostRecentTransaction(addressString);
return "" + addressString
+ " balance: " + format("%13s", stringFormattedBalance)
+ ((balance > 0) ? (" confirmations: " + format("%6d", numConfirmations)) : "");
})
.collect(Collectors.joining("\n"));
}

public int getNumConfirmationsForMostRecentTransaction(String addressString) {
Expand Down Expand Up @@ -285,4 +266,18 @@ private AddressEntry getAddressEntry(String addressString) {

return addressEntry.get();
}

/**
* Memoization stores the results of expensive function calls and returns
* the cached result when the same input occurs again.
*
* Resulting LoadingCache is used by calling `.get(input I)` or
* `.getUnchecked(input I)`, depending on whether or not `f` can return null.
* That's because CacheLoader throws an exception on null output from `f`.
*/
private static <I, O> LoadingCache<I, O> memoize(Function<I, O> f) {
// f::apply is used, because Guava 20.0 Function doesn't yet extend
// Java Function.
return CacheBuilder.newBuilder().build(CacheLoader.from(f::apply));
}
}

0 comments on commit b0e278f

Please sign in to comment.