diff --git a/core/src/main/java/com/google/bitcoin/core/Wallet.java b/core/src/main/java/com/google/bitcoin/core/Wallet.java index 56dc0f1d..744f517b 100644 --- a/core/src/main/java/com/google/bitcoin/core/Wallet.java +++ b/core/src/main/java/com/google/bitcoin/core/Wallet.java @@ -19,6 +19,7 @@ package com.google.bitcoin.core; import com.google.bitcoin.crypto.KeyCrypterScrypt; import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.Multimap; +import com.google.common.util.concurrent.SettableFuture; import org.bitcoinj.wallet.Protos.Wallet.EncryptionType; import org.spongycastle.crypto.params.KeyParameter; @@ -2807,6 +2808,45 @@ public class Wallet implements Serializable, BlockChainListener { setCoinSelector(Wallet.AllowUnconfirmedCoinSelector.get()); } + /** + * Returns a future that will complete when the balance of the given type is equal or larger to the given value. + * If the wallet already has a large enough balance the future is returned in a pre-completed state. Note that this + * method is not blocking, if you want to actually wait immediately, you have to call .get() on the result. + */ + public ListenableFuture waitForBalance(final BigInteger value, final BalanceType type) { + final SettableFuture future = SettableFuture.create(); + final BigInteger current = getBalance(type); + if (current.compareTo(value) >= 0) { + // Already have enough. + future.set(current); + return future; + } + addEventListener(new AbstractWalletEventListener() { + private boolean done = false; + + @Override + public void onTransactionConfidenceChanged(Wallet wallet, Transaction tx) { + check(); + } + + private void check() { + final BigInteger newBalance = getBalance(type); + if (!done && newBalance.compareTo(value) >= 0) { + // Have enough now. + done = true; + removeEventListener(this); + future.set(newBalance); + } + } + + @Override + public void onCoinsReceived(Wallet w, Transaction t, BigInteger b1, BigInteger b2) { + check(); + } + }); + return future; + } + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // Boilerplate for running event listeners - unlocks the wallet, runs, re-locks. diff --git a/core/src/test/java/com/google/bitcoin/core/WalletTest.java b/core/src/test/java/com/google/bitcoin/core/WalletTest.java index 38ff9668..640fac21 100644 --- a/core/src/test/java/com/google/bitcoin/core/WalletTest.java +++ b/core/src/test/java/com/google/bitcoin/core/WalletTest.java @@ -22,6 +22,7 @@ import com.google.bitcoin.crypto.KeyCrypter; import com.google.bitcoin.crypto.KeyCrypterException; import com.google.bitcoin.crypto.KeyCrypterScrypt; import com.google.common.collect.Lists; +import com.google.common.util.concurrent.ListenableFuture; import com.google.protobuf.ByteString; import org.bitcoinj.wallet.Protos; @@ -175,9 +176,15 @@ public class WalletTest extends TestWithWallet { private void receiveAPendingTransaction(Wallet wallet, Address toAddress) throws Exception { BigInteger v1 = Utils.toNanoCoins(1, 0); + final ListenableFuture availFuture = wallet.waitForBalance(v1, Wallet.BalanceType.AVAILABLE); + final ListenableFuture estimatedFuture = wallet.waitForBalance(v1, Wallet.BalanceType.ESTIMATED); + assertFalse(availFuture.isDone()); + assertFalse(estimatedFuture.isDone()); Transaction t1 = sendMoneyToWallet(wallet, v1, toAddress, null); assertEquals(BigInteger.ZERO, wallet.getBalance()); assertEquals(v1, wallet.getBalance(Wallet.BalanceType.ESTIMATED)); + assertFalse(availFuture.isDone()); + assertTrue(estimatedFuture.isDone()); assertEquals(1, wallet.getPoolSize(Pool.PENDING)); assertEquals(0, wallet.getPoolSize(WalletTransaction.Pool.UNSPENT)); sendMoneyToWallet(wallet, t1, AbstractBlockChain.NewBlockType.BEST_CHAIN); @@ -185,6 +192,8 @@ public class WalletTest extends TestWithWallet { assertEquals("Incorrect confirmed tx PENDING pool size", 0, wallet.getPoolSize(WalletTransaction.Pool.PENDING)); assertEquals("Incorrect confirmed tx UNSPENT pool size", 1, wallet.getPoolSize(WalletTransaction.Pool.UNSPENT)); assertEquals("Incorrect confirmed tx ALL pool size", 1, wallet.getPoolSize(WalletTransaction.Pool.ALL)); + assertTrue(availFuture.isDone()); + assertTrue(estimatedFuture.isDone()); } private void basicSanityChecks(Wallet wallet, Transaction t, Address fromAddress, Address destination) throws ScriptException {