Skip to content

Commit

Permalink
Merge pull request #2 from dmos62/Z-getfundingaddresses-patch
Browse files Browse the repository at this point in the history
Refactor getFundingAddresses to use memoization
  • Loading branch information
ghubstan committed Jun 18, 2020
2 parents 258d180 + c5134e1 commit 9db9ee2
Showing 1 changed file with 53 additions and 36 deletions.
89 changes: 53 additions & 36 deletions core/src/main/java/bisq/core/grpc/CoreWalletsService.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@

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 Down Expand Up @@ -88,6 +92,20 @@ 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())
throw new IllegalStateException("wallet is not yet available");
Expand All @@ -98,44 +116,43 @@ public String getFundingAddresses() {
if (btcWalletService.getAvailableAddressEntries().size() == 0)
btcWalletService.getFreshAddressEntry();

// Populate a list of Tuple3<AddressString, Balance, NumConfirmations>
List<Tuple3<String, Long, Integer>> addrBalanceConfirms =
btcWalletService.getAvailableAddressEntries().stream()
.map(a -> new Tuple3<>(a.getAddressString(),
getAddressBalance(a.getAddressString()),
getNumConfirmationsForMostRecentTransaction(a.getAddressString())))
.collect(Collectors.toList());

// Check to see if at least one of the existing addresses has a zero balance.
boolean hasZeroBalance = false;
for (Tuple3<String, Long, Integer> abc : addrBalanceConfirms) {
if (abc.second == 0) {
hasZeroBalance = true;
break;
}
}
if (!hasZeroBalance) {
// None of the existing addresses have a zero balance, create a new address.
addrBalanceConfirms.add(
new Tuple3<>(btcWalletService.getFreshAddressEntry().getAddressString(),
0L,
0));
List<String> addressStrings =
btcWalletService
.getAvailableAddressEntries()
.stream()
.map(addressEntry -> 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);

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

// Iterate the list of Tuple3<AddressString, Balance, NumConfirmations> objects
// and build the formatted info string.
StringBuilder addressInfoBuilder = new StringBuilder();
addrBalanceConfirms.forEach(a -> {
var btcBalance = formatSatoshis.apply(a.second);
var numConfirmations = getNumConfirmationsForMostRecentTransaction(a.first);
String addressInfo = "" + a.first
+ " balance: " + format("%13s", btcBalance)
+ ((a.second > 0) ? (" confirmations: " + format("%6d", numConfirmations)) : "")
+ "\n";
addressInfoBuilder.append(addressInfo);
});

return addressInfoBuilder.toString().trim();
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;
}

public int getNumConfirmationsForMostRecentTransaction(String addressString) {
Expand Down

0 comments on commit 9db9ee2

Please sign in to comment.