mirror of
https://github.com/Qortal/altcoinj.git
synced 2025-08-01 12:31:23 +00:00
DeterministicKeyChain.Builder: Handle a custom accountPath.
Use that feature to get rid of DeterministicKeyChainTest.AccountOneChain and AccountTwoChain.
This commit is contained in:
@@ -28,7 +28,7 @@ public class DefaultKeyChainFactory implements KeyChainFactory {
|
|||||||
public DeterministicKeyChain makeKeyChain(Protos.Key key, Protos.Key firstSubKey, DeterministicSeed seed, KeyCrypter crypter, boolean isMarried) {
|
public DeterministicKeyChain makeKeyChain(Protos.Key key, Protos.Key firstSubKey, DeterministicSeed seed, KeyCrypter crypter, boolean isMarried) {
|
||||||
DeterministicKeyChain chain;
|
DeterministicKeyChain chain;
|
||||||
if (isMarried)
|
if (isMarried)
|
||||||
chain = new MarriedKeyChain(seed, crypter);
|
chain = new MarriedKeyChain(seed, crypter, null);
|
||||||
else
|
else
|
||||||
chain = new DeterministicKeyChain(seed, crypter);
|
chain = new DeterministicKeyChain(seed, crypter);
|
||||||
return chain;
|
return chain;
|
||||||
@@ -39,7 +39,7 @@ public class DefaultKeyChainFactory implements KeyChainFactory {
|
|||||||
KeyCrypter crypter, boolean isMarried, ImmutableList<ChildNumber> accountPath) {
|
KeyCrypter crypter, boolean isMarried, ImmutableList<ChildNumber> accountPath) {
|
||||||
DeterministicKeyChain chain;
|
DeterministicKeyChain chain;
|
||||||
if (isMarried)
|
if (isMarried)
|
||||||
chain = new MarriedKeyChain(seed, crypter);
|
chain = new MarriedKeyChain(seed, crypter, accountPath);
|
||||||
else
|
else
|
||||||
chain = new DeterministicKeyChain(seed, crypter, accountPath);
|
chain = new DeterministicKeyChain(seed, crypter, accountPath);
|
||||||
return chain;
|
return chain;
|
||||||
|
@@ -167,7 +167,8 @@ public class DeterministicKeyChain implements EncryptableKeyChain {
|
|||||||
protected long seedCreationTimeSecs;
|
protected long seedCreationTimeSecs;
|
||||||
protected byte[] entropy;
|
protected byte[] entropy;
|
||||||
protected DeterministicSeed seed;
|
protected DeterministicSeed seed;
|
||||||
protected DeterministicKey watchingKey;
|
protected DeterministicKey watchingKey = null;
|
||||||
|
protected ImmutableList<ChildNumber> accountPath = null;
|
||||||
|
|
||||||
protected Builder() {
|
protected Builder() {
|
||||||
}
|
}
|
||||||
@@ -221,6 +222,7 @@ public class DeterministicKeyChain implements EncryptableKeyChain {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public T watchingKey(DeterministicKey watchingKey) {
|
public T watchingKey(DeterministicKey watchingKey) {
|
||||||
|
checkState(accountPath == null, "either watchingKey or accountPath");
|
||||||
this.watchingKey = watchingKey;
|
this.watchingKey = watchingKey;
|
||||||
return self();
|
return self();
|
||||||
}
|
}
|
||||||
@@ -237,19 +239,31 @@ public class DeterministicKeyChain implements EncryptableKeyChain {
|
|||||||
return self();
|
return self();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use an account path other than the default {@link DeterministicKeyChain#ACCOUNT_ZERO_PATH}.
|
||||||
|
*/
|
||||||
|
public T accountPath(ImmutableList<ChildNumber> accountPath) {
|
||||||
|
checkState(watchingKey == null, "either watchingKey or accountPath");
|
||||||
|
this.accountPath = accountPath;
|
||||||
|
return self();
|
||||||
|
}
|
||||||
|
|
||||||
public DeterministicKeyChain build() {
|
public DeterministicKeyChain build() {
|
||||||
checkState(random != null || entropy != null || seed != null || watchingKey!= null, "Must provide either entropy or random or seed or watchingKey");
|
checkState(random != null || entropy != null || seed != null || watchingKey!= null, "Must provide either entropy or random or seed or watchingKey");
|
||||||
checkState(passphrase == null || seed == null, "Passphrase must not be specified with seed");
|
checkState(passphrase == null || seed == null, "Passphrase must not be specified with seed");
|
||||||
DeterministicKeyChain chain;
|
|
||||||
|
|
||||||
|
if (accountPath == null)
|
||||||
|
accountPath = ACCOUNT_ZERO_PATH;
|
||||||
|
|
||||||
|
DeterministicKeyChain chain;
|
||||||
if (random != null) {
|
if (random != null) {
|
||||||
// Default passphrase to "" if not specified
|
// Default passphrase to "" if not specified
|
||||||
chain = new DeterministicKeyChain(random, bits, getPassphrase(), seedCreationTimeSecs);
|
chain = new DeterministicKeyChain(new DeterministicSeed(random, bits, getPassphrase(), seedCreationTimeSecs), null, accountPath);
|
||||||
} else if (entropy != null) {
|
} else if (entropy != null) {
|
||||||
chain = new DeterministicKeyChain(entropy, getPassphrase(), seedCreationTimeSecs);
|
chain = new DeterministicKeyChain(new DeterministicSeed(entropy, getPassphrase(), seedCreationTimeSecs), null, accountPath);
|
||||||
} else if (seed != null) {
|
} else if (seed != null) {
|
||||||
seed.setCreationTimeSeconds(seedCreationTimeSecs);
|
seed.setCreationTimeSeconds(seedCreationTimeSecs);
|
||||||
chain = new DeterministicKeyChain(seed);
|
chain = new DeterministicKeyChain(seed, null, accountPath);
|
||||||
} else {
|
} else {
|
||||||
watchingKey.setCreationTimeSeconds(seedCreationTimeSecs);
|
watchingKey.setCreationTimeSeconds(seedCreationTimeSecs);
|
||||||
chain = new DeterministicKeyChain(watchingKey);
|
chain = new DeterministicKeyChain(watchingKey);
|
||||||
|
@@ -24,6 +24,7 @@ import org.bitcoinj.core.BloomFilter;
|
|||||||
import org.bitcoinj.core.ECKey;
|
import org.bitcoinj.core.ECKey;
|
||||||
import org.bitcoinj.core.NetworkParameters;
|
import org.bitcoinj.core.NetworkParameters;
|
||||||
import org.bitcoinj.core.Utils;
|
import org.bitcoinj.core.Utils;
|
||||||
|
import org.bitcoinj.crypto.ChildNumber;
|
||||||
import org.bitcoinj.crypto.DeterministicKey;
|
import org.bitcoinj.crypto.DeterministicKey;
|
||||||
import org.bitcoinj.crypto.KeyCrypter;
|
import org.bitcoinj.crypto.KeyCrypter;
|
||||||
import org.bitcoinj.script.Script;
|
import org.bitcoinj.script.Script;
|
||||||
@@ -95,16 +96,20 @@ public class MarriedKeyChain extends DeterministicKeyChain {
|
|||||||
public MarriedKeyChain build() {
|
public MarriedKeyChain build() {
|
||||||
checkState(random != null || entropy != null || seed != null || watchingKey!= null, "Must provide either entropy or random or seed or watchingKey");
|
checkState(random != null || entropy != null || seed != null || watchingKey!= null, "Must provide either entropy or random or seed or watchingKey");
|
||||||
checkNotNull(followingKeys, "followingKeys must be provided");
|
checkNotNull(followingKeys, "followingKeys must be provided");
|
||||||
MarriedKeyChain chain;
|
|
||||||
if (threshold == 0)
|
if (threshold == 0)
|
||||||
threshold = (followingKeys.size() + 1) / 2 + 1;
|
threshold = (followingKeys.size() + 1) / 2 + 1;
|
||||||
|
if (accountPath == null)
|
||||||
|
accountPath = ACCOUNT_ZERO_PATH;
|
||||||
|
|
||||||
|
MarriedKeyChain chain;
|
||||||
if (random != null) {
|
if (random != null) {
|
||||||
chain = new MarriedKeyChain(random, bits, getPassphrase(), seedCreationTimeSecs);
|
chain = new MarriedKeyChain(new DeterministicSeed(random, bits, getPassphrase(), seedCreationTimeSecs), null, accountPath);
|
||||||
} else if (entropy != null) {
|
} else if (entropy != null) {
|
||||||
chain = new MarriedKeyChain(entropy, getPassphrase(), seedCreationTimeSecs);
|
chain = new MarriedKeyChain(new DeterministicSeed(entropy, getPassphrase(), seedCreationTimeSecs), null, accountPath);
|
||||||
} else if (seed != null) {
|
} else if (seed != null) {
|
||||||
seed.setCreationTimeSeconds(seedCreationTimeSecs);
|
seed.setCreationTimeSeconds(seedCreationTimeSecs);
|
||||||
chain = new MarriedKeyChain(seed);
|
chain = new MarriedKeyChain(seed, null, accountPath);
|
||||||
} else {
|
} else {
|
||||||
watchingKey.setCreationTimeSeconds(seedCreationTimeSecs);
|
watchingKey.setCreationTimeSeconds(seedCreationTimeSecs);
|
||||||
chain = new MarriedKeyChain(watchingKey);
|
chain = new MarriedKeyChain(watchingKey);
|
||||||
@@ -123,8 +128,8 @@ public class MarriedKeyChain extends DeterministicKeyChain {
|
|||||||
super(accountKey, false);
|
super(accountKey, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
MarriedKeyChain(DeterministicSeed seed, KeyCrypter crypter) {
|
protected MarriedKeyChain(DeterministicSeed seed, KeyCrypter crypter, ImmutableList<ChildNumber> accountPath) {
|
||||||
super(seed, crypter);
|
super(seed, crypter, accountPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Builder constructors
|
// Builder constructors
|
||||||
|
@@ -105,7 +105,8 @@ public class DeterministicKeyChainTest {
|
|||||||
@Test
|
@Test
|
||||||
public void deriveAccountOne() throws Exception {
|
public void deriveAccountOne() throws Exception {
|
||||||
long secs = 1389353062L;
|
long secs = 1389353062L;
|
||||||
DeterministicKeyChain chain1 = new AccountOneChain(ENTROPY, "", secs);
|
DeterministicKeyChain chain1 = DeterministicKeyChain.builder().accountPath(ImmutableList.of(ChildNumber.ONE))
|
||||||
|
.entropy(ENTROPY).seedCreationTimeSecs(secs).build();
|
||||||
ECKey key1 = chain1.getKey(KeyChain.KeyPurpose.RECEIVE_FUNDS);
|
ECKey key1 = chain1.getKey(KeyChain.KeyPurpose.RECEIVE_FUNDS);
|
||||||
ECKey key2 = chain1.getKey(KeyChain.KeyPurpose.RECEIVE_FUNDS);
|
ECKey key2 = chain1.getKey(KeyChain.KeyPurpose.RECEIVE_FUNDS);
|
||||||
|
|
||||||
@@ -122,25 +123,11 @@ public class DeterministicKeyChainTest {
|
|||||||
key3.sign(Sha256Hash.ZERO_HASH);
|
key3.sign(Sha256Hash.ZERO_HASH);
|
||||||
}
|
}
|
||||||
|
|
||||||
static class AccountOneChain extends DeterministicKeyChain {
|
|
||||||
public AccountOneChain(byte[] entropy, String s, long secs) {
|
|
||||||
super(entropy, s, secs);
|
|
||||||
}
|
|
||||||
|
|
||||||
public AccountOneChain(KeyCrypter crypter, DeterministicSeed seed) {
|
|
||||||
super(seed, crypter);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected ImmutableList<ChildNumber> getAccountPath() {
|
|
||||||
return ImmutableList.of(ChildNumber.ONE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void serializeAccountOne() throws Exception {
|
public void serializeAccountOne() throws Exception {
|
||||||
long secs = 1389353062L;
|
long secs = 1389353062L;
|
||||||
DeterministicKeyChain chain1 = new AccountOneChain(ENTROPY, "", secs);
|
DeterministicKeyChain chain1 = DeterministicKeyChain.builder().accountPath(ImmutableList.of(ChildNumber.ONE))
|
||||||
|
.entropy(ENTROPY).seedCreationTimeSecs(secs).build();
|
||||||
ECKey key1 = chain1.getKey(KeyChain.KeyPurpose.RECEIVE_FUNDS);
|
ECKey key1 = chain1.getKey(KeyChain.KeyPurpose.RECEIVE_FUNDS);
|
||||||
|
|
||||||
final Address address = LegacyAddress.fromBase58(UNITTEST, "n2nHHRHs7TiZScTuVhZUkzZfTfVgGYwy6X");
|
final Address address = LegacyAddress.fromBase58(UNITTEST, "n2nHHRHs7TiZScTuVhZUkzZfTfVgGYwy6X");
|
||||||
@@ -153,12 +140,12 @@ public class DeterministicKeyChainTest {
|
|||||||
@Override
|
@Override
|
||||||
public DeterministicKeyChain makeKeyChain(Protos.Key key, Protos.Key firstSubKey, DeterministicSeed seed,
|
public DeterministicKeyChain makeKeyChain(Protos.Key key, Protos.Key firstSubKey, DeterministicSeed seed,
|
||||||
KeyCrypter crypter, boolean isMarried, ImmutableList<ChildNumber> accountPath) {
|
KeyCrypter crypter, boolean isMarried, ImmutableList<ChildNumber> accountPath) {
|
||||||
return new AccountOneChain(crypter, seed);
|
return DeterministicKeyChain.builder().seed(seed).accountPath(accountPath).build();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DeterministicKeyChain makeKeyChain(Protos.Key key, Protos.Key firstSubKey, DeterministicSeed seed, KeyCrypter crypter, boolean isMarried) {
|
public DeterministicKeyChain makeKeyChain(Protos.Key key, Protos.Key firstSubKey, DeterministicSeed seed, KeyCrypter crypter, boolean isMarried) {
|
||||||
return new AccountOneChain(crypter, seed);
|
return DeterministicKeyChain.builder().seed(seed).build();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -450,7 +437,8 @@ public class DeterministicKeyChainTest {
|
|||||||
@Test
|
@Test
|
||||||
public void watchingChainAccountOne() throws UnreadableWalletException {
|
public void watchingChainAccountOne() throws UnreadableWalletException {
|
||||||
Utils.setMockClock();
|
Utils.setMockClock();
|
||||||
DeterministicKeyChain chain1 = new AccountOneChain(chain.getKeyCrypter(), chain.getSeed());
|
DeterministicKeyChain chain1 = DeterministicKeyChain.builder().accountPath(ImmutableList.of(ChildNumber.ONE))
|
||||||
|
.seed(chain.getSeed()).build();
|
||||||
DeterministicKey key1 = chain1.getKey(KeyChain.KeyPurpose.RECEIVE_FUNDS);
|
DeterministicKey key1 = chain1.getKey(KeyChain.KeyPurpose.RECEIVE_FUNDS);
|
||||||
DeterministicKey key2 = chain1.getKey(KeyChain.KeyPurpose.RECEIVE_FUNDS);
|
DeterministicKey key2 = chain1.getKey(KeyChain.KeyPurpose.RECEIVE_FUNDS);
|
||||||
DeterministicKey key3 = chain1.getKey(KeyChain.KeyPurpose.CHANGE);
|
DeterministicKey key3 = chain1.getKey(KeyChain.KeyPurpose.CHANGE);
|
||||||
@@ -521,26 +509,13 @@ public class DeterministicKeyChainTest {
|
|||||||
final DeterministicKey rekey4 = chain.getKey(KeyChain.KeyPurpose.CHANGE);
|
final DeterministicKey rekey4 = chain.getKey(KeyChain.KeyPurpose.CHANGE);
|
||||||
assertEquals(key4.getPubKeyPoint(), rekey4.getPubKeyPoint());
|
assertEquals(key4.getPubKeyPoint(), rekey4.getPubKeyPoint());
|
||||||
}
|
}
|
||||||
static class AccountTwoChain extends DeterministicKeyChain {
|
|
||||||
public AccountTwoChain(byte[] entropy, String s, long secs) {
|
|
||||||
super(entropy, s, secs);
|
|
||||||
}
|
|
||||||
|
|
||||||
public AccountTwoChain(KeyCrypter crypter, DeterministicSeed seed) {
|
|
||||||
super(seed, crypter);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected ImmutableList<ChildNumber> getAccountPath() {
|
|
||||||
return ImmutableList.of(new ChildNumber(2, true));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void spendingChainAccountTwo() throws UnreadableWalletException {
|
public void spendingChainAccountTwo() throws UnreadableWalletException {
|
||||||
Utils.setMockClock();
|
Utils.setMockClock();
|
||||||
long secs = 1389353062L;
|
long secs = 1389353062L;
|
||||||
chain = new AccountTwoChain(ENTROPY, "", secs);
|
chain = DeterministicKeyChain.builder().accountPath(ImmutableList.of(new ChildNumber(2, true))).entropy(ENTROPY)
|
||||||
|
.seedCreationTimeSecs(secs).build();
|
||||||
DeterministicKey firstReceiveKey = chain.getKey(KeyChain.KeyPurpose.RECEIVE_FUNDS);
|
DeterministicKey firstReceiveKey = chain.getKey(KeyChain.KeyPurpose.RECEIVE_FUNDS);
|
||||||
DeterministicKey secondReceiveKey = chain.getKey(KeyChain.KeyPurpose.RECEIVE_FUNDS);
|
DeterministicKey secondReceiveKey = chain.getKey(KeyChain.KeyPurpose.RECEIVE_FUNDS);
|
||||||
DeterministicKey firstChangeKey = chain.getKey(KeyChain.KeyPurpose.CHANGE);
|
DeterministicKey firstChangeKey = chain.getKey(KeyChain.KeyPurpose.CHANGE);
|
||||||
|
Reference in New Issue
Block a user