mirror of
https://github.com/Qortal/altcoinj.git
synced 2025-02-15 11:45:51 +00:00
Add Wallet.isWatching() to determine if the wallet is a watching wallet. Comes with tests.
This commit is contained in:
parent
1e6ce4b1ba
commit
ed6821ed15
@ -401,6 +401,11 @@ public class ECKey implements EncryptableItem, Serializable {
|
||||
return priv != null;
|
||||
}
|
||||
|
||||
/** Returns true if this key is watch only, meaning it has a public key but no private key. */
|
||||
public boolean isWatching() {
|
||||
return isPubKeyOnly() && !isEncrypted();
|
||||
}
|
||||
|
||||
/**
|
||||
* Output this ECKey as an ASN.1 encoded private key, as understood by OpenSSL or used by the Bitcoin reference
|
||||
* implementation in its wallet storage format.
|
||||
|
@ -750,6 +750,23 @@ public class Wallet extends BaseTaggableObject implements Serializable, BlockCha
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this wallet consists entirely of watching keys (unencrypted keys with no private part). Mixed
|
||||
* wallets are forbidden.
|
||||
*
|
||||
* @throws IllegalStateException
|
||||
* if there are no keys, or if there is a mix between watching and non-watching keys.
|
||||
*/
|
||||
public boolean isWatching() {
|
||||
keychainLock.lock();
|
||||
try {
|
||||
maybeUpgradeToHD();
|
||||
return keychain.isWatching();
|
||||
} finally {
|
||||
keychainLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if we are watching this address.
|
||||
*/
|
||||
|
@ -47,6 +47,7 @@ public class BasicKeyChain implements EncryptableKeyChain {
|
||||
private final LinkedHashMap<ByteString, ECKey> hashToKeys;
|
||||
private final LinkedHashMap<ByteString, ECKey> pubkeyToKeys;
|
||||
@Nullable private final KeyCrypter keyCrypter;
|
||||
private boolean isWatching;
|
||||
|
||||
private final CopyOnWriteArrayList<ListenerRegistration<KeyChainEventListener>> listeners;
|
||||
|
||||
@ -167,6 +168,14 @@ public class BasicKeyChain implements EncryptableKeyChain {
|
||||
}
|
||||
|
||||
private void importKeyLocked(ECKey key) {
|
||||
if (hashToKeys.isEmpty()) {
|
||||
isWatching = key.isWatching();
|
||||
} else {
|
||||
if (key.isWatching() && !isWatching)
|
||||
throw new IllegalArgumentException("Key is watching but chain is not");
|
||||
if (!key.isWatching() && isWatching)
|
||||
throw new IllegalArgumentException("Key is not watching but chain is");
|
||||
}
|
||||
ECKey previousKey = pubkeyToKeys.put(ByteString.copyFrom(key.getPubKey()), key);
|
||||
hashToKeys.put(ByteString.copyFrom(key.getPubKeyHash()), key);
|
||||
checkState(previousKey == null);
|
||||
@ -221,6 +230,21 @@ public class BasicKeyChain implements EncryptableKeyChain {
|
||||
return pubkeyToKeys.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this chain consists entirely of watching keys (unencrypted keys with no private part). Mixed
|
||||
* chains are forbidden. Null means the chain is empty.
|
||||
*/
|
||||
public Boolean isWatching() {
|
||||
lock.lock();
|
||||
try {
|
||||
if (hashToKeys.isEmpty())
|
||||
return null;
|
||||
return isWatching;
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the given key from the keychain. Be very careful with this - losing a private key <b>destroys the
|
||||
* money associated with it</b>.
|
||||
|
@ -628,6 +628,12 @@ public class DeterministicKeyChain implements EncryptableKeyChain {
|
||||
return getKeyByPath(ACCOUNT_ZERO_PATH);
|
||||
}
|
||||
|
||||
/** Returns true if this chain is watch only, meaning it has public keys but no private key. */
|
||||
public boolean isWatching() {
|
||||
DeterministicKey key = getKeyByPath(ACCOUNT_ZERO_PATH);
|
||||
return key.isWatching();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int numKeys() {
|
||||
// We need to return here the total number of keys including the lookahead zone, not the number of keys we
|
||||
|
@ -551,6 +551,30 @@ public class KeyChainGroup implements KeyBag {
|
||||
return keyCrypter != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this chain has only watching keys (unencrypted keys with no private part). Mixed chains are
|
||||
* forbidden.
|
||||
*
|
||||
* @throws IllegalStateException
|
||||
* if there are no keys, or if there is a mix between watching and non-watching keys.
|
||||
*/
|
||||
public boolean isWatching() {
|
||||
Boolean basicChainIsWatching = basic.isWatching();
|
||||
Boolean deterministicChainIsWatching = !chains.isEmpty() ? getActiveKeyChain().isWatching() : null;
|
||||
if (basicChainIsWatching == null && deterministicChainIsWatching == null)
|
||||
throw new IllegalStateException("No keys");
|
||||
if (basicChainIsWatching == null && deterministicChainIsWatching != null)
|
||||
return deterministicChainIsWatching;
|
||||
if (basicChainIsWatching != null && deterministicChainIsWatching == null)
|
||||
return basicChainIsWatching;
|
||||
if (basicChainIsWatching == deterministicChainIsWatching)
|
||||
return deterministicChainIsWatching;
|
||||
if (basicChainIsWatching && !deterministicChainIsWatching)
|
||||
throw new IllegalStateException("Basic chain is watching, deterministic chain is not");
|
||||
else
|
||||
throw new IllegalStateException("Basic chain is not watching, deterministic chain is");
|
||||
}
|
||||
|
||||
/** Returns the key crypter or null if the group is not encrypted. */
|
||||
@Nullable public KeyCrypter getKeyCrypter() { return keyCrypter; }
|
||||
|
||||
|
@ -77,7 +77,7 @@ public class BloomFilterTest {
|
||||
|
||||
KeyChainGroup group = new KeyChainGroup(params);
|
||||
// Add a random key which happens to have been used in a recent generation
|
||||
group.importKeys(privKey.getKey(), ECKey.fromPublicOnly(HEX.decode("03cb219f69f1b49468bd563239a86667e74a06fcba69ac50a08a5cbc42a5808e99")));
|
||||
group.importKeys(ECKey.fromPublicOnly(privKey.getKey().getPubKeyPoint()), ECKey.fromPublicOnly(HEX.decode("03cb219f69f1b49468bd563239a86667e74a06fcba69ac50a08a5cbc42a5808e99")));
|
||||
Wallet wallet = new Wallet(context, group);
|
||||
wallet.commitTx(new Transaction(params, HEX.decode("01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0d038754030114062f503253482fffffffff01c05e559500000000232103cb219f69f1b49468bd563239a86667e74a06fcba69ac50a08a5cbc42a5808e99ac00000000")));
|
||||
|
||||
|
@ -1152,6 +1152,15 @@ public class WalletTest extends TestWithWallet {
|
||||
log.info(t2.toString(chain));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isWatching() {
|
||||
assertFalse(wallet.isWatching());
|
||||
Wallet watchingWallet = Wallet.fromWatchingKey(params, wallet.getWatchingKey().dropPrivateBytes().dropParent());
|
||||
assertTrue(watchingWallet.isWatching());
|
||||
wallet.encrypt(PASSWORD1);
|
||||
assertFalse(wallet.isWatching());
|
||||
}
|
||||
|
||||
@Test(expected = ECKey.MissingPrivateKeyException.class)
|
||||
public void watchingWallet() throws Exception {
|
||||
DeterministicKey watchKey = wallet.getWatchingKey();
|
||||
|
@ -148,6 +148,7 @@ public class BasicKeyChainTest {
|
||||
ECKey key = chain.findKeyFromPubKey(key1.getPubKey());
|
||||
assertTrue(key.isEncrypted());
|
||||
assertTrue(key.isPubKeyOnly());
|
||||
assertFalse(key.isWatching());
|
||||
assertNull(key.getSecretBytes());
|
||||
|
||||
try {
|
||||
@ -165,6 +166,7 @@ public class BasicKeyChainTest {
|
||||
key = chain.findKeyFromPubKey(key1.getPubKey());
|
||||
assertFalse(key.isEncrypted());
|
||||
assertFalse(key.isPubKeyOnly());
|
||||
assertFalse(key.isWatching());
|
||||
key.getPrivKeyBytes();
|
||||
}
|
||||
|
||||
|
@ -27,6 +27,7 @@ import org.junit.Test;
|
||||
import org.spongycastle.crypto.params.KeyParameter;
|
||||
import org.spongycastle.util.Arrays;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
@ -582,4 +583,44 @@ public class KeyChainGroupTest {
|
||||
Address addr3 = group.currentAddress(KeyChain.KeyPurpose.RECEIVE_FUNDS);
|
||||
assertNotEquals(addr2, addr3);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isNotWatching() {
|
||||
group = new KeyChainGroup(params);
|
||||
final ECKey key = ECKey.fromPrivate(BigInteger.TEN);
|
||||
group.importKeys(key);
|
||||
assertFalse(group.isWatching());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isWatching() {
|
||||
group = new KeyChainGroup(
|
||||
params,
|
||||
DeterministicKey
|
||||
.deserializeB58(
|
||||
"xpub69bjfJ91ikC5ghsqsVDHNq2dRGaV2HHVx7Y9LXi27LN9BWWAXPTQr4u8U3wAtap8bLdHdkqPpAcZmhMS5SnrMQC4ccaoBccFhh315P4UYzo",
|
||||
params));
|
||||
final ECKey watchingKey = ECKey.fromPublicOnly(new ECKey().getPubKeyPoint());
|
||||
group.importKeys(watchingKey);
|
||||
assertTrue(group.isWatching());
|
||||
}
|
||||
|
||||
@Test(expected = IllegalStateException.class)
|
||||
public void isWatchingNoKeys() {
|
||||
group = new KeyChainGroup(params);
|
||||
group.isWatching();
|
||||
}
|
||||
|
||||
@Test(expected = IllegalStateException.class)
|
||||
public void isWatchingMixedKeys() {
|
||||
group = new KeyChainGroup(
|
||||
params,
|
||||
DeterministicKey
|
||||
.deserializeB58(
|
||||
"xpub69bjfJ91ikC5ghsqsVDHNq2dRGaV2HHVx7Y9LXi27LN9BWWAXPTQr4u8U3wAtap8bLdHdkqPpAcZmhMS5SnrMQC4ccaoBccFhh315P4UYzo",
|
||||
params));
|
||||
final ECKey key = ECKey.fromPrivate(BigInteger.TEN);
|
||||
group.importKeys(key);
|
||||
group.isWatching();
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user