WalletTool: convert wait() to return CompletableFuture

This change:
1. Shortens the code by 5 lines while adding many comments
2. Separates output to System.out from the async wait handling
3. Separates wallet/peerGroup setup and starting from async wait handling
4. Passes wait condition (along with wait-type enum) as a parameter

Behavior should be unchanged with the exception that the balance will
be output in the case that it "already meets the given condition".
This commit is contained in:
Sean Gilligan 2023-05-23 02:06:57 -07:00 committed by Andreas Schildbach
parent b8bfbcc658
commit d7c20ff73d

View file

@ -96,8 +96,8 @@ import java.util.Objects;
import java.util.Optional; import java.util.Optional;
import java.util.concurrent.Callable; import java.util.concurrent.Callable;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.function.Consumer;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.LogManager; import java.util.logging.LogManager;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -495,7 +495,11 @@ public class WalletTool implements Callable<Integer> {
saveWallet(walletFile); saveWallet(walletFile);
if (waitFor != null) { if (waitFor != null) {
wait(waitFor); setup();
CompletableFuture<String> futureMessage = wait(waitFor, condition);
if (!peerGroup.isRunning())
peerGroup.startAsync();
System.out.println(futureMessage.join());
if (!wallet.isConsistent()) { if (!wallet.isConsistent()) {
System.err.println("************** WALLET IS INCONSISTENT *****************"); System.err.println("************** WALLET IS INCONSISTENT *****************");
return 10; return 10;
@ -912,48 +916,46 @@ public class WalletTool implements Callable<Integer> {
} }
} }
private void wait(WaitForEnum waitFor) throws BlockStoreException { /**
final CountDownLatch latch = new CountDownLatch(1); * Wait for a condition to be satisfied
setup(); * @param waitFor condition type to wait for
* @param condition balance condition to wait for
* @return A (future) human-readable message (txId, block hash, or balance) to display when wait is complete
*/
private CompletableFuture<String> wait(WaitForEnum waitFor, Condition condition) {
CompletableFuture<String> future = new CompletableFuture<>();
switch (waitFor) { switch (waitFor) {
case EVER: case EVER:
break; break; // Future will never complete
case WALLET_TX: case WALLET_TX:
wallet.addCoinsReceivedEventListener((wallet, tx, prevBalance, newBalance) -> { // Future will complete with a transaction ID string
// Runs in a peer thread. Consumer<Transaction> txListener = tx -> future.complete(tx.getTxId().toString());
System.out.println(tx.getTxId()); // Both listeners run in a peer thread
latch.countDown(); // Wake up main thread. wallet.addCoinsReceivedEventListener((wallet, tx, prevBalance, newBalance) -> txListener.accept(tx));
}); wallet.addCoinsSentEventListener((wallet, tx, prevBalance, newBalance) -> txListener.accept(tx));
wallet.addCoinsSentEventListener((wallet, tx, prevBalance, newBalance) -> {
// Runs in a peer thread.
System.out.println(tx.getTxId());
latch.countDown(); // Wake up main thread.
});
break; break;
case BLOCK: case BLOCK:
peerGroup.addBlocksDownloadedEventListener((peer, block, filteredBlock, blocksLeft) -> { // Future will complete with a Block hash string
// Check if we already ran. This can happen if a block being received triggers download of more peerGroup.addBlocksDownloadedEventListener((peer, block, filteredBlock, blocksLeft) ->
// blocks, or if we receive another block whilst the peer group is shutting down. future.complete(block.getHashAsString())
if (latch.getCount() == 0) return; );
System.out.println(block.getHashAsString());
latch.countDown();
});
break; break;
case BALANCE: case BALANCE:
// Future will complete with a balance amount string
// Check if the balance already meets the given condition. // Check if the balance already meets the given condition.
if (condition.matchBitcoins(wallet.getBalance(Wallet.BalanceType.ESTIMATED))) { Coin existingBalance = wallet.getBalance(Wallet.BalanceType.ESTIMATED);
latch.countDown(); if (condition.matchBitcoins(existingBalance)) {
future.complete(existingBalance.toFriendlyString());
} else { } else {
Runnable onChange = () -> { Runnable onChange = () -> {
synchronized (this) { synchronized (this) {
saveWallet(walletFile); saveWallet(walletFile);
Coin balance = wallet.getBalance(Wallet.BalanceType.ESTIMATED); Coin balance = wallet.getBalance(Wallet.BalanceType.ESTIMATED);
if (condition.matchBitcoins(balance)) { if (condition.matchBitcoins(balance)) {
System.out.println(balance.toFriendlyString()); future.complete(balance.toFriendlyString());
latch.countDown();
} }
} }
}; };
@ -963,15 +965,8 @@ public class WalletTool implements Callable<Integer> {
wallet.addReorganizeEventListener(w -> onChange.run()); wallet.addReorganizeEventListener(w -> onChange.run());
} }
break; break;
}
if (!peerGroup.isRunning())
peerGroup.startAsync();
try {
latch.await();
} catch (InterruptedException e) {
// Ignore.
} }
return future;
} }
private void reset() { private void reset() {