From 5840c8a66a9b895ae063075d30bc7107ef2f996f Mon Sep 17 00:00:00 2001 From: troggy <7r0ggy@gmail.com> Date: Wed, 11 Jun 2014 23:53:45 +0400 Subject: [PATCH] Fix failing deserialization of wallet with an empty HD chain Error occurred when deserializing wallet if either internal or external zero account key chain of this wallet has no keys issued --- .../google/bitcoin/wallet/KeyChainGroup.java | 22 ++++++++++++------- .../bitcoin/wallet/KeyChainGroupTest.java | 1 + 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/core/src/main/java/com/google/bitcoin/wallet/KeyChainGroup.java b/core/src/main/java/com/google/bitcoin/wallet/KeyChainGroup.java index 66d60698..a80f3761 100644 --- a/core/src/main/java/com/google/bitcoin/wallet/KeyChainGroup.java +++ b/core/src/main/java/com/google/bitcoin/wallet/KeyChainGroup.java @@ -468,19 +468,25 @@ public class KeyChainGroup { private static EnumMap createCurrentKeysMap(List chains) { DeterministicKeyChain activeChain = chains.get(chains.size() - 1); - DeterministicKey currentExternalKey = activeChain.getKeyByPath( - ImmutableList.of(ChildNumber.ZERO_HARDENED, ChildNumber.ZERO, new ChildNumber(activeChain.getIssuedExternalKeys() - 1)) - ); - DeterministicKey currentInternalKey = activeChain.getKeyByPath( - ImmutableList.of(ChildNumber.ZERO_HARDENED, new ChildNumber(1), new ChildNumber(activeChain.getIssuedInternalKeys() - 1)) - ); EnumMap currentKeys = new EnumMap(KeyChain.KeyPurpose.class); + // assuming that only RECEIVE and CHANGE keys are being used at the moment, we will treat latest issued external key // as current RECEIVE key and latest issued internal key as CHANGE key. This should be changed as soon as other // kinds of KeyPurpose are introduced. - currentKeys.put(KeyChain.KeyPurpose.RECEIVE_FUNDS, currentExternalKey); - currentKeys.put(KeyChain.KeyPurpose.CHANGE, currentInternalKey); + if (activeChain.getIssuedExternalKeys() > 0) { + DeterministicKey currentExternalKey = activeChain.getKeyByPath( + ImmutableList.of(ChildNumber.ZERO_HARDENED, ChildNumber.ZERO, new ChildNumber(activeChain.getIssuedExternalKeys() - 1)) + ); + currentKeys.put(KeyChain.KeyPurpose.RECEIVE_FUNDS, currentExternalKey); + } + + if (activeChain.getIssuedInternalKeys() > 0) { + DeterministicKey currentInternalKey = activeChain.getKeyByPath( + ImmutableList.of(ChildNumber.ZERO_HARDENED, new ChildNumber(1), new ChildNumber(activeChain.getIssuedInternalKeys() - 1)) + ); + currentKeys.put(KeyChain.KeyPurpose.CHANGE, currentInternalKey); + } return currentKeys; } diff --git a/core/src/test/java/com/google/bitcoin/wallet/KeyChainGroupTest.java b/core/src/test/java/com/google/bitcoin/wallet/KeyChainGroupTest.java index 742b99be..cacb7122 100644 --- a/core/src/test/java/com/google/bitcoin/wallet/KeyChainGroupTest.java +++ b/core/src/test/java/com/google/bitcoin/wallet/KeyChainGroupTest.java @@ -284,6 +284,7 @@ public class KeyChainGroupTest { @Test public void serialization() throws Exception { assertEquals(INITIAL_KEYS + 1 /* for the seed */, group.serializeToProtobuf().size()); + group = KeyChainGroup.fromProtobufUnencrypted(group.serializeToProtobuf()); group.freshKey(KeyChain.KeyPurpose.RECEIVE_FUNDS); DeterministicKey key1 = group.freshKey(KeyChain.KeyPurpose.RECEIVE_FUNDS); DeterministicKey key2 = group.freshKey(KeyChain.KeyPurpose.CHANGE);