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 38a2e309..da6b1cbd 100644 --- a/core/src/main/java/com/google/bitcoin/core/Wallet.java +++ b/core/src/main/java/com/google/bitcoin/core/Wallet.java @@ -17,7 +17,6 @@ package com.google.bitcoin.core; import com.google.bitcoin.core.TransactionConfidence.ConfidenceType; -import com.google.bitcoin.wallet.WalletTransaction.Pool; import com.google.bitcoin.crypto.KeyCrypter; import com.google.bitcoin.crypto.KeyCrypterException; import com.google.bitcoin.crypto.KeyCrypterScrypt; @@ -29,6 +28,7 @@ import com.google.bitcoin.store.WalletProtobufSerializer; import com.google.bitcoin.utils.ListenerRegistration; import com.google.bitcoin.utils.Threading; import com.google.bitcoin.wallet.*; +import com.google.bitcoin.wallet.WalletTransaction.Pool; import com.google.common.collect.*; import com.google.common.primitives.Ints; import com.google.common.util.concurrent.FutureCallback; @@ -190,14 +190,6 @@ public class Wallet implements Serializable, BlockChainListener, PeerFilterProvi * see loadFromFile. */ public Wallet(NetworkParameters params) { - this(params, null); - } - - /** - * Create a wallet with a keyCrypter to use in encrypting and decrypting keys. - */ - public Wallet(NetworkParameters params, KeyCrypter keyCrypter) { - this.keyCrypter = keyCrypter; this.params = checkNotNull(params); keychain = new ArrayList(); watchedScripts = Sets.newHashSet(); @@ -212,6 +204,14 @@ public class Wallet implements Serializable, BlockChainListener, PeerFilterProvi createTransientState(); } + /** + * Create a wallet with a keyCrypter to use in encrypting and decrypting keys. + */ + public Wallet(NetworkParameters params, KeyCrypter keyCrypter) { + this(params); + this.keyCrypter = checkNotNull(keyCrypter); + } + private void createTransientState() { ignoreNextNewBlock = new HashSet(); txConfidenceListener = new TransactionConfidence.Listener() { @@ -1593,7 +1593,9 @@ public class Wallet implements Serializable, BlockChainListener, PeerFilterProvi */ public static SendRequest to(Address destination, BigInteger value) { SendRequest req = new SendRequest(); - req.tx = new Transaction(destination.getParameters()); + final NetworkParameters parameters = destination.getParameters(); + checkNotNull(parameters, "Address is for an unknown network"); + req.tx = new Transaction(parameters); req.tx.addOutput(value, destination); return req; } @@ -1622,7 +1624,9 @@ public class Wallet implements Serializable, BlockChainListener, PeerFilterProvi public static SendRequest emptyWallet(Address destination) { SendRequest req = new SendRequest(); - req.tx = new Transaction(destination.getParameters()); + final NetworkParameters parameters = destination.getParameters(); + checkNotNull(parameters, "Address is for an unknown network"); + req.tx = new Transaction(parameters); req.tx.addOutput(BigInteger.ZERO, destination); req.emptyWallet = true; return req; @@ -1768,7 +1772,6 @@ public class Wallet implements Serializable, BlockChainListener, PeerFilterProvi * * @return The {@link Transaction} that was created or null if there was insufficient balance to send the coins. * @throws InsufficientMoneyException if the request could not be completed due to not enough balance. - * @throws IOException if there was a problem broadcasting the transaction */ public Transaction sendCoins(Peer peer, SendRequest request) throws InsufficientMoneyException { Transaction tx = sendCoinsOffline(request); @@ -2099,6 +2102,7 @@ public class Wallet implements Serializable, BlockChainListener, PeerFilterProvi * * @return ECKey object or null if no such key was found. */ + @Nullable public ECKey findKeyFromPubHash(byte[] pubkeyHash) { lock.lock(); try { @@ -2142,6 +2146,7 @@ public class Wallet implements Serializable, BlockChainListener, PeerFilterProvi * Locates a keypair from the keychain given the raw public key bytes. * @return ECKey or null if no such key was found. */ + @Nullable public ECKey findKeyFromPubKey(byte[] pubkey) { lock.lock(); try { @@ -2334,7 +2339,7 @@ public class Wallet implements Serializable, BlockChainListener, PeerFilterProvi } private void toStringHelper(StringBuilder builder, Map transactionMap, - AbstractBlockChain chain) { + @Nullable AbstractBlockChain chain) { checkState(lock.isHeldByCurrentThread()); for (Transaction tx : transactionMap.values()) { try { @@ -2811,11 +2816,7 @@ public class Wallet implements Serializable, BlockChainListener, PeerFilterProvi public boolean checkPassword(CharSequence password) { lock.lock(); try { - if (keyCrypter == null) { - // The password cannot decrypt anything as the keyCrypter is null. - return false; - } - return checkAESKey(keyCrypter.deriveKey(checkNotNull(password))); + return keyCrypter != null && checkAESKey(keyCrypter.deriveKey(checkNotNull(password))); } finally { lock.unlock(); } @@ -3513,15 +3514,16 @@ public class Wallet implements Serializable, BlockChainListener, PeerFilterProvi try { if (output.getScriptPubKey().isSentToAddress()) { // Send-to-address spends usually take maximum pubkey.length (as it may be compressed or not) + 75 bytes - size += findKeyFromPubHash(output.getScriptPubKey().getPubKeyHash()).getPubKey().length + 75; + final ECKey key = findKeyFromPubHash(output.getScriptPubKey().getPubKeyHash()); + size += checkNotNull(key, "Coin selection includes unspendable outputs").getPubKey().length + 75; } else if (output.getScriptPubKey().isSentToRawPubKey()) size += 74; // Send-to-pubkey spends usually take maximum 74 bytes to spend else - throw new RuntimeException("Unknown output type returned in coin selection"); + throw new IllegalStateException("Unknown output type returned in coin selection"); } catch (ScriptException e) { // If this happens it means an output script in a wallet tx could not be understood. That should never // happen, if it does it means the wallet has got into an inconsistent state. - throw new RuntimeException(e); + throw new IllegalStateException(e); } } return size; @@ -3636,6 +3638,7 @@ public class Wallet implements Serializable, BlockChainListener, PeerFilterProvi } while (tx != null && tx.getInputs().size() == KeyTimeCoinSelector.MAX_SIMULTANEOUS_INPUTS); } + @Nullable private Transaction rekeyOneBatch(long keyRotationTimestamp, final TransactionBroadcaster broadcaster) { final Transaction rekeyTx; @@ -3652,7 +3655,8 @@ public class Wallet implements Serializable, BlockChainListener, PeerFilterProvi safeKey = key; } } - if (!haveRotatingKeys) return null; + if (!haveRotatingKeys) + return null; if (safeKey == null) { log.warn("Key rotation requested but no keys newer than the timestamp are available."); return null;