3
0
mirror of https://github.com/Qortal/altcoinj.git synced 2025-02-14 19:25:51 +00:00

Remove unnecessary accountPath parameter on watch key methods while preserving that the watched key account path can be arbitrary (does not have to be 0H).

This commit is contained in:
HashEngineering 2018-01-31 21:51:56 -08:00 committed by Andreas Schildbach
parent 4d0f15dc2e
commit be382c6800
6 changed files with 313 additions and 62 deletions

View File

@ -48,11 +48,14 @@ public class DefaultKeyChainFactory implements KeyChainFactory {
@Override
public DeterministicKeyChain makeWatchingKeyChain(Protos.Key key, Protos.Key firstSubKey, DeterministicKey accountKey,
boolean isFollowingKey, boolean isMarried) throws UnreadableWalletException {
if (accountKey.getPath().size() != DeterministicKeyChain.ACCOUNT_ZERO_PATH.size())
throw new UnreadableWalletException("Expecting account key but found key with path: " +
HDUtils.formatPath(accountKey.getPath()));
DeterministicKeyChain chain;
if (isMarried)
chain = new MarriedKeyChain(accountKey);
else
chain = new DeterministicKeyChain(accountKey, isFollowingKey, accountKey.getPath());
chain = new DeterministicKeyChain(accountKey, isFollowingKey);
return chain;
}
}

View File

@ -322,17 +322,9 @@ public class DeterministicKeyChain implements EncryptableKeyChain {
* balances and generally follow along, but spending is not possible with such a chain.
*/
public DeterministicKeyChain(DeterministicKey watchingKey) {
this(watchingKey, ACCOUNT_ZERO_PATH);
}
/**
* Creates a deterministic key chain that watches the given (public only) root key. You can use this to calculate
* balances and generally follow along, but spending is not possible with such a chain.
*/
public DeterministicKeyChain(DeterministicKey watchingKey, ImmutableList<ChildNumber> accountPath) {
checkArgument(watchingKey.isPubKeyOnly(), "Private subtrees not currently supported: if you got this key from DKC.getWatchingKey() then use .dropPrivate().dropParent() on it first.");
checkArgument(watchingKey.getPath().size() == accountPath.size(), "You can only watch an account key currently");
setAccountPath(accountPath);
checkArgument(watchingKey.getPath().size() == getAccountPath().size(), "You can only watch an account key currently");
setAccountPath(watchingKey.getPath());
basicKeyChain = new BasicKeyChain();
this.seed = null;
this.rootKey = null;
@ -347,17 +339,7 @@ public class DeterministicKeyChain implements EncryptableKeyChain {
* <p>Watch key has to be an account key.</p>
*/
protected DeterministicKeyChain(DeterministicKey watchKey, boolean isFollowing) {
this(watchKey, isFollowing, ACCOUNT_ZERO_PATH);
}
/**
* <p>Creates a deterministic key chain with the given watch key. If <code>isFollowing</code> flag is set then this keychain follows
* some other keychain. In a married wallet following keychain represents "spouse's" keychain.</p>
* <p>Watch key has to be an account key.</p>
*/
protected DeterministicKeyChain(DeterministicKey watchKey, boolean isFollowing,
ImmutableList<ChildNumber> accountPath) {
this(watchKey, accountPath);
this(watchKey);
this.isFollowing = isFollowing;
}
@ -374,14 +356,7 @@ public class DeterministicKeyChain implements EncryptableKeyChain {
* Creates a key chain that watches the given account key.
*/
public static DeterministicKeyChain watch(DeterministicKey accountKey) {
return watch(accountKey, ACCOUNT_ZERO_PATH);
}
/**
* Creates a key chain that watches the given account key.
*/
public static DeterministicKeyChain watch(DeterministicKey accountKey, ImmutableList<ChildNumber> accountPath) {
return new DeterministicKeyChain(accountKey, accountPath);
return new DeterministicKeyChain(accountKey);
}
/**

View File

@ -100,14 +100,6 @@ public class KeyChainGroup implements KeyBag {
this(params, null, ImmutableList.of(DeterministicKeyChain.watch(watchKey)), null, null);
}
/**
* Creates a keychain group with no basic chain, and an HD chain that is watching the given watching key.
* This HAS to be an account key as returned by {@link DeterministicKeyChain#getWatchingKey()}.
*/
public KeyChainGroup(NetworkParameters params, DeterministicKey watchKey, ImmutableList<ChildNumber> accountPath) {
this(params, null, ImmutableList.of(DeterministicKeyChain.watch(watchKey, accountPath)), null, null);
}
// Used for deserialization.
private KeyChainGroup(NetworkParameters params, @Nullable BasicKeyChain basicKeyChain, List<DeterministicKeyChain> chains,
@Nullable EnumMap<KeyChain.KeyPurpose, DeterministicKey> currentKeys, @Nullable KeyCrypter crypter) {

View File

@ -287,42 +287,21 @@ public class Wallet extends BaseTaggableObject
}
/**
* Creates a wallet that tracks payments to and from the HD key hierarchy rooted by the given watching key. A
* watching key corresponds to account zero in the recommended BIP32 key hierarchy.
* Creates a wallet that tracks payments to and from the HD key hierarchy rooted by the given watching key.
*/
public static Wallet fromWatchingKey(NetworkParameters params, DeterministicKey watchKey) {
return new Wallet(params, new KeyChainGroup(params, watchKey));
}
/**
* Creates a wallet that tracks payments to and from the HD key hierarchy rooted by the given watching key. The account path is specified.
*/
public static Wallet fromWatchingKey(NetworkParameters params, DeterministicKey watchKey, ImmutableList<ChildNumber> accountPath) {
return new Wallet(params, new KeyChainGroup(params, watchKey, accountPath));
}
/**
* Creates a wallet that tracks payments to and from the HD key hierarchy rooted by the given watching key. A
* watching key corresponds to account zero in the recommended BIP32 key hierarchy. The key is specified in base58
* notation and the creation time of the key. If you don't know the creation time, you can pass
* {@link DeterministicHierarchy#BIP32_STANDARDISATION_TIME_SECS}.
*/
public static Wallet fromWatchingKeyB58(NetworkParameters params, String watchKeyB58, long creationTimeSeconds) {
final DeterministicKey watchKey = DeterministicKey.deserializeB58(null, watchKeyB58, params);
watchKey.setCreationTimeSeconds(creationTimeSeconds);
return fromWatchingKey(params, watchKey);
}
/**
* Creates a wallet that tracks payments to and from the HD key hierarchy rooted by the given watching key. The
* account path is specified. The key is specified in base58 notation and the creation time of the key. If you don't
* know the creation time, you can pass {@link DeterministicHierarchy#BIP32_STANDARDISATION_TIME_SECS}.
*/
public static Wallet fromWatchingKeyB58(NetworkParameters params, String watchKeyB58, long creationTimeSeconds,
ImmutableList<ChildNumber> accountPath) {
public static Wallet fromWatchingKeyB58(NetworkParameters params, String watchKeyB58, long creationTimeSeconds) {
final DeterministicKey watchKey = DeterministicKey.deserializeB58(null, watchKeyB58, params);
watchKey.setCreationTimeSeconds(creationTimeSeconds);
return fromWatchingKey(params, watchKey, accountPath);
return fromWatchingKey(params, watchKey);
}
/**

View File

@ -395,6 +395,45 @@ public class DeterministicKeyChainTest {
assertEquals(key4.getPubKeyPoint(), rekey4.getPubKeyPoint());
}
@Test
public void watchingChainAccountOne() throws UnreadableWalletException {
Utils.setMockClock();
DeterministicKeyChain chain1 = new AccountOneChain(chain.getKeyCrypter(), chain.getSeed());
DeterministicKey key1 = chain1.getKey(KeyChain.KeyPurpose.RECEIVE_FUNDS);
DeterministicKey key2 = chain1.getKey(KeyChain.KeyPurpose.RECEIVE_FUNDS);
DeterministicKey key3 = chain1.getKey(KeyChain.KeyPurpose.CHANGE);
DeterministicKey key4 = chain1.getKey(KeyChain.KeyPurpose.CHANGE);
NetworkParameters params = MainNetParams.get();
DeterministicKey watchingKey = chain1.getWatchingKey();
final String pub58 = watchingKey.serializePubB58(params);
assertEquals("xpub69KR9epJ2Wp6ywiv4Xu5WfBUpX4GLu6D5NUMd4oUkCFoZoRNyk3ZCxfKPDkkGvCPa16dPgEdY63qoyLqEa5TQQy1nmfSmgWcagRzimyV7uA", pub58);
watchingKey = DeterministicKey.deserializeB58(null, pub58, params);
watchingKey.setCreationTimeSeconds(100000);
chain = DeterministicKeyChain.watch(watchingKey);
assertEquals(100000, chain.getEarliestKeyCreationTime());
chain.setLookaheadSize(10);
chain.maybeLookAhead();
assertEquals(key1.getPubKeyPoint(), chain.getKey(KeyChain.KeyPurpose.RECEIVE_FUNDS).getPubKeyPoint());
assertEquals(key2.getPubKeyPoint(), chain.getKey(KeyChain.KeyPurpose.RECEIVE_FUNDS).getPubKeyPoint());
final DeterministicKey key = chain.getKey(KeyChain.KeyPurpose.CHANGE);
assertEquals(key3.getPubKeyPoint(), key.getPubKeyPoint());
try {
// Can't sign with a key from a watching chain.
key.sign(Sha256Hash.ZERO_HASH);
fail();
} catch (ECKey.MissingPrivateKeyException e) {
// Ignored.
}
// Test we can serialize and deserialize a watching chain OK.
List<Protos.Key> serialization = chain.serializeToProtobuf();
checkSerialization(serialization, "watching-wallet-serialization-account-one.txt");
chain = DeterministicKeyChain.fromProtobuf(serialization, null).get(0);
final DeterministicKey rekey4 = chain.getKey(KeyChain.KeyPurpose.CHANGE);
assertEquals(key4.getPubKeyPoint(), rekey4.getPubKeyPoint());
}
@Test(expected = IllegalStateException.class)
public void watchingCannotEncrypt() throws Exception {
final DeterministicKey accountKey = chain.getKeyByPath(DeterministicKeyChain.ACCOUNT_ZERO_PATH);

View File

@ -0,0 +1,263 @@
type: DETERMINISTIC_KEY
public_key: "\002\221 {7k\345UH\324x)\006.)\201\363$\376\vN\215J\336\315\021\245\351w!\336\004\034"
creation_timestamp: 100000000
deterministic_key {
chain_code: "SE\031\000\277\023 \256W\237\036\034c\340\aB-I\246\304\025\325\262\314\235\240]\020\374T\315\027"
path: 1
}
type: DETERMINISTIC_KEY
public_key: "\003QO{n\351\326\357\343T\203u\345\025{]\231\234\273A\376U`\307\212\336h\255\215\335(\364\001"
deterministic_key {
chain_code: "\375y\345\372\243\305\021\000p\325\320\232\277\022?\245\024\027\262T\364z\206\204C\216E\376C\275\\\b"
path: 1
path: 0
issued_subkeys: 2
lookahead_size: 10
sigsRequiredToSpend: 1
}
type: DETERMINISTIC_KEY
public_key: "\003\006\371Ph\\*\342)*\232]\272\322\261\256<x0S\306\017\372\003z\313::\3369k&\364"
deterministic_key {
chain_code: "B\217\f\n\276F\2269\246\004n\312\267\242\375\240[\254/ICl\256\242`\211\314i\321\367\351\347"
path: 1
path: 1
issued_subkeys: 1
lookahead_size: 10
sigsRequiredToSpend: 1
}
type: DETERMINISTIC_KEY
public_key: "\003\206\215r6b\023\341\263\302\3122\256\001d\373\263=\270\2263\376\376\032\277\332\001*\272l\350\215\030"
deterministic_key {
chain_code: "\a\254j\211\355w\217\361\003Gm\242\\\302\0226\255HH@\201\363\251S\314\004\005\266\207\306\360D"
path: 1
path: 0
path: 0
}
type: DETERMINISTIC_KEY
public_key: "\002-\264\264X2\272\227\032&\313\027O\242\f\f\032\3041\330]s\200\236\206\324\235AF\337\356\260"
deterministic_key {
chain_code: "\311\031\200\276\242te\217\3703%\227|V\341E\025D\244cd\277\022<\260\2350i4\236\220\367"
path: 1
path: 0
path: 1
}
type: DETERMINISTIC_KEY
public_key: "\003\252\264.\253\304\257\346}\3167\357\030\022\273!;E\242\343dO\"u\200mU\336\242\202\036;\274"
deterministic_key {
chain_code: "\036\321\205\277:\027o\210&\244Q\231.\365\002\264\273\210?k\214\372\303Et\261\261\276\037\344OB"
path: 1
path: 0
path: 2
}
type: DETERMINISTIC_KEY
public_key: "\003\350\214\322\274\216\250\261\362o\025g\221\256\264\262/\356\362G\217\f\231\332\304\210h\201\025\234\253\'7"
deterministic_key {
chain_code: "\351\032_O\376^q\263!\273\342\006x\206W\023\336\325R\246V\300\277\216\036Rm\bQaA\216"
path: 1
path: 0
path: 3
}
type: DETERMINISTIC_KEY
public_key: "\003\\\363^\306\036s\\F2f\213\376\234\255s/\216m\032\210\r@\005\227\216\'R3-\264\332\347"
deterministic_key {
chain_code: "o\b$\004\221;w|\353\253SL\r\305\261\307\2001\260s\361\347\207\371\000)\261\357\275b\360\265"
path: 1
path: 0
path: 4
}
type: DETERMINISTIC_KEY
public_key: "\003|\353\226\017/\030E\320m\322\236\352\257\304{\360\r\346\221I\001,*\230\275h\363N\314E\016X"
deterministic_key {
chain_code: "l\325\253]\2638u\362\200\251\301Y\242S\242]\252\363e\373\2258\254\255(\230\3652\030\350\027\020"
path: 1
path: 0
path: 5
}
type: DETERMINISTIC_KEY
public_key: "\002,\"\246\243\304\'\021\002#S\rk\332\334\003\371\351\323\330\r3b\000\264\271\2420\3261\325\242/"
deterministic_key {
chain_code: "\230\226\2270\360,\335\r\267\325I\t>\240\020\025\005\270\026\3636\246\342\200\240f\005\234\244\v\221\""
path: 1
path: 0
path: 6
}
type: DETERMINISTIC_KEY
public_key: "\003\v\370\324\n\332V\311\260\375U\261`\271/{\216\246\230\267\243\2664\001{\226\bP\265\"\273\356\'"
deterministic_key {
chain_code: "\033\227\342\017\027O\205\2462\322\321\021\314vX\255+\3465\as\246T6\231\227G\273\n\221\355\002"
path: 1
path: 0
path: 7
}
type: DETERMINISTIC_KEY
public_key: "\003o\244\334\344\3278f_\251\r\f\035d\326\251\300\231\206\032oL\323\320\254\'\336y\201N\364\265\017"
deterministic_key {
chain_code: "ET\204]\017A\360_iHv\364\332\tO\354c\031\002\0301eI\236`\304\366\332i0\003\375"
path: 1
path: 0
path: 8
}
type: DETERMINISTIC_KEY
public_key: "\003;\234\200F\370\217\277\2652\265Y\276%\020\226\304x\321\350\313v\316J,\373.\224\213\317\367\326\353"
deterministic_key {
chain_code: "\260\3533#\203\322\376\322\301\233\260B\334\304\235_\342=\246\300\266\0234\345r\203\213\2576|\311"
path: 1
path: 0
path: 9
}
type: DETERMINISTIC_KEY
public_key: "\002\274Q\024Q\312\364\244\363~J\346\2250\nl\334\274\200\247\016\345;4u&\022tAY#MN"
deterministic_key {
chain_code: "\357\025!\243\025Z\3614\327\310\211\3624\026\n\032\233\256\362\250\376\370>\tb)\340\357\3621\362"
path: 1
path: 0
path: 10
}
type: DETERMINISTIC_KEY
public_key: "\002\375\231\206\364\364m\v\232\230\233\355\001\357\237\237\214\343b\235\212\320E\261\tF \227\250y\a\3026"
deterministic_key {
chain_code: "\3525>2\r\261\t\217H\f6 L\262\304$N\250JZ\0019\037\033w\201f,\371,s\342"
path: 1
path: 0
path: 11
}
type: DETERMINISTIC_KEY
public_key: "\003\362\021\026v`\310\333e\375\331\nE\r\242Z\337\321w(\316z\n\017#1F\323\302\317\370f\313"
deterministic_key {
chain_code: "\205\302e\221\250\f\3705\233\303\261H\324\366\376\v\354g\333\031*J\267\226\303\347\037\354\275k\t\276"
path: 1
path: 0
path: 12
}
type: DETERMINISTIC_KEY
public_key: "\002B\236[KR\272\273\315\030_\362V\272\252\245(\352m\276\020\260\027\365\362mM\b\265gq.M"
deterministic_key {
chain_code: ",?\220\362\246\20356\321\250\276\3739<\334u\320\221\033qC\214\024id\252!6\375k\036]"
path: 1
path: 1
path: 0
}
type: DETERMINISTIC_KEY
public_key: "\002&\2323!\301\254,\210e\"\222\"\357b\300u\341\000\275VDV\026\210\222U\277\016y\202@\240"
deterministic_key {
chain_code: "\fj\300\'\227\fo\036N\r\370\004,\201\270\023m:E\335-\331I\032\032\203\310o\236\261\213\213"
path: 1
path: 1
path: 1
}
type: DETERMINISTIC_KEY
public_key: "\003\341\331\037\216I\026O\2271\316\301+IZ\\\004\225V\331\231\312\022Df\232_t}B\v\365\232"
deterministic_key {
chain_code: "4YZ\277<\247\003\304\2672TS\362\b&\201\306\024\220\253\260m\267\001Y\201\342X\310R{x"
path: 1
path: 1
path: 2
}
type: DETERMINISTIC_KEY
public_key: "\003-/ \26795Z\000\341\363\346\377:#\026A\001\335X:\r!K\000\275\005\251\203\260\024\016\377"
deterministic_key {
chain_code: "\271\320\211\260W\fq\365\t\305\026!\n\364\362\0228\230\212\350\252\\\0048\250\n\017\231\244\334\344\341"
path: 1
path: 1
path: 3
}
type: DETERMINISTIC_KEY
public_key: "\002\\g\216\026\342\204\226z4K\330\a@yST\341c=\233r\224\0379\211I\347\341\363\333\264\263"
deterministic_key {
chain_code: ">\341z\r\212\206\351{\221\353\337d\266\364y=\t\230\264.\302\321/\002\2140\017\244\271\361\362\226"
path: 1
path: 1
path: 4
}
type: DETERMINISTIC_KEY
public_key: "\003GT\304l\350R\352\300\220\f\275_\223\201\374oU\327mx}\232\252-l\t\270\303\027O>\366"
deterministic_key {
chain_code: "\2423\212H\335-\232\v:\330\307\227L\313\272.x\344\242\363\331\034y[\003>\323\276\334\033@\341"
path: 1
path: 1
path: 5
}
type: DETERMINISTIC_KEY
public_key: "\003\254\200U0\2106sb\305\3456\'\027\204\02716q\251\215*$\232S\'\303\375\272\325V\342Q"
deterministic_key {
chain_code: "{i\034\237\236\233SE,\247\301\343\255J%\232\201\303\031\203=\303,D\313Pp6\f\r/\333"
path: 1
path: 1
path: 6
}
type: DETERMINISTIC_KEY
public_key: "\002\366\265^\241\263<_\316\036S]C\225S;\233\004\002E\a\261\324\004\336\003\276\345a\002>\311\233"
deterministic_key {
chain_code: "\244\327\315\353\231\371 \302/\227\320\303D\207\033@^\334\024\223;\220{\355G\236k\220\303\320zL"
path: 1
path: 1
path: 7
}
type: DETERMINISTIC_KEY
public_key: "\002\243I\215\246\2358PN\3238A\262\370i\031\206\266\202!`h\221\274\r\344\220\\,\350;)\300"
deterministic_key {
chain_code: "]/6\360\n\t\356\\B:Zs\317\274\363]\034`N\237`\337\340\277\347\001\231v:,\340\224"
path: 1
path: 1
path: 8
}
type: DETERMINISTIC_KEY
public_key: "\002\302rf\260E\306\303\205\271\222\222\315\364\317br\237\345w&\254}\314\363H\317fv\247\203\250\372"
deterministic_key {
chain_code: ",\270\243\347Q\340U\tx\270\214S\306\205\312\242Y\302\0168\002\366\343\316\"&\034W\352\330\245\357"
path: 1
path: 1
path: 9
}
type: DETERMINISTIC_KEY
public_key: "\002\\\207\256\270oNU\203M\f/z\334\003\353\310A\226m#\321!\313E\237\361\310\211\255\376\316\262"
deterministic_key {
chain_code: "\245\336+\332\307\342q\356)0\350\004mz\215\321\001U\2059g\200\247\240\252\fQ\341\276J\303"
path: 1
path: 1
path: 10
}
type: DETERMINISTIC_KEY
public_key: "\002G\327\343 \210A\356\354\233\276\277\341\311\352F}D}F\233\000bu(\333\343\002\277\033\272\243\232"
deterministic_key {
chain_code: "\301\261\333\361\275\255FE4k\224\301\302\325\223\272\216]D*f~\233\305\350\212\3678\242\262\257H"
path: 1
path: 1
path: 11
}
type: DETERMINISTIC_KEY
public_key: "\002\366\2432<_\361\026W\372\f\004\224\027\367\360\346\347M\377\271\207\264\233\234\001I\340\322`Y\216k"
deterministic_key {
chain_code: "c\324M\225h\242\374\021o~[\203\212\343wxVs\226\343\025\316\243|}\t\350\330\242*\247\\"
path: 1
path: 1
path: 12
}