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 07d3f4cd..5e158396 100644 --- a/core/src/main/java/com/google/bitcoin/core/Wallet.java +++ b/core/src/main/java/com/google/bitcoin/core/Wallet.java @@ -288,6 +288,7 @@ public class Wallet extends BaseTaggableObject implements Serializable, BlockCha public DeterministicKey currentKey(KeyChain.KeyPurpose purpose) { lock.lock(); try { + maybeUpgradeToHD(); return keychain.currentKey(purpose); } finally { lock.unlock(); @@ -308,6 +309,7 @@ public class Wallet extends BaseTaggableObject implements Serializable, BlockCha public Address currentAddress(KeyChain.KeyPurpose purpose) { lock.lock(); try { + maybeUpgradeToHD(); return keychain.currentAddress(purpose, params); } finally { lock.unlock(); @@ -345,20 +347,8 @@ public class Wallet extends BaseTaggableObject implements Serializable, BlockCha public List freshKeys(KeyChain.KeyPurpose purpose, int numberOfKeys) { lock.lock(); try { - List keys; - try { - keys = keychain.freshKeys(purpose, numberOfKeys); - } catch (DeterministicUpgradeRequiredException e) { - log.info("Attempt to request a fresh HD key on a non-upgraded wallet, trying to upgrade ..."); - try { - upgradeToDeterministic(null); - keys = keychain.freshKeys(purpose, numberOfKeys); - } catch (DeterministicUpgradeRequiresPassword e2) { - // Nope, can't do it. Rethrow the original exception. - log.error("Failed to auto upgrade because wallet is encrypted, giving up. You should call wallet.upgradeToDeterministic yourself to avoid this situation."); - throw e; - } - } + maybeUpgradeToHD(); + List keys = keychain.freshKeys(purpose, numberOfKeys); // Do we really need an immediate hard save? Arguably all this is doing is saving the 'current' key // and that's not quite so important, so we could coalesce for more performance. saveNow(); @@ -382,6 +372,7 @@ public class Wallet extends BaseTaggableObject implements Serializable, BlockCha public Address freshAddress(KeyChain.KeyPurpose purpose) { lock.lock(); try { + maybeUpgradeToHD(); Address key = keychain.freshAddress(purpose, params); saveNow(); return key; @@ -429,6 +420,20 @@ public class Wallet extends BaseTaggableObject implements Serializable, BlockCha } } + private void maybeUpgradeToHD() throws DeterministicUpgradeRequiresPassword { + checkState(lock.isHeldByCurrentThread()); + if (keychain.isDeterministicUpgradeRequired()) { + log.info("Upgrade to HD wallets is required, attempting to do so."); + try { + upgradeToDeterministic(null); + } catch (DeterministicUpgradeRequiresPassword e) { + log.error("Failed to auto upgrade due to encryption. You should call wallet.upgradeToDeterministic " + + "with the users AES key to avoid this error."); + throw e; + } + } + } + /** * Returns a snapshot of the watched scripts. This view is not live. */ @@ -569,6 +574,7 @@ public class Wallet extends BaseTaggableObject implements Serializable, BlockCha public void setKeychainLookaheadThreshold(int num) { lock.lock(); try { + maybeUpgradeToHD(); keychain.setLookaheadThreshold(num); } finally { lock.unlock(); @@ -579,6 +585,7 @@ public class Wallet extends BaseTaggableObject implements Serializable, BlockCha public int getKeychainLookaheadThreshold() { lock.lock(); try { + maybeUpgradeToHD(); return keychain.getLookaheadThreshold(); } finally { lock.unlock(); @@ -593,6 +600,7 @@ public class Wallet extends BaseTaggableObject implements Serializable, BlockCha public DeterministicKey getWatchingKey() { lock.lock(); try { + maybeUpgradeToHD(); return keychain.getActiveKeyChain().getWatchingKey(); } finally { lock.unlock(); diff --git a/core/src/main/java/com/google/bitcoin/wallet/DeterministicUpgradeRequiresPassword.java b/core/src/main/java/com/google/bitcoin/wallet/DeterministicUpgradeRequiresPassword.java index 70998dff..6ca4c0bc 100644 --- a/core/src/main/java/com/google/bitcoin/wallet/DeterministicUpgradeRequiresPassword.java +++ b/core/src/main/java/com/google/bitcoin/wallet/DeterministicUpgradeRequiresPassword.java @@ -5,4 +5,4 @@ package com.google.bitcoin.wallet; * users password. This is required because HD wallets are upgraded from random using the private key bytes of * the oldest non-rotating key, in order to make the upgrade process itself deterministic. */ -public class DeterministicUpgradeRequiresPassword extends Exception {} +public class DeterministicUpgradeRequiresPassword extends RuntimeException {}