mirror of
https://github.com/bitcoinj/bitcoinj.git
synced 2024-11-20 10:12:19 +01:00
HD Wallets: mark the DeterministicKeys as issued, if seen in a Transaction
If a Transaction contains a DeterministicKey of our DeterministicKeyChains, then we should mark this key as issued. This can happen, when we replay/resync the blockchain or when another device uses one of our keys. Signed-off-by: Harald Hoyer <harald@harald-hoyer.de>
This commit is contained in:
parent
534a1e3a5c
commit
5726b97f70
@ -637,6 +637,33 @@ public class Wallet extends BaseTaggableObject implements Serializable, BlockCha
|
||||
return findKeyFromPubKey(pubkey) != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks all keys used in the transaction output as used in the wallet.
|
||||
* See {@link com.google.bitcoin.wallet.DeterministicKeyChain#markKeyAsUsed(DeterministicKey)} for more info on this.
|
||||
*/
|
||||
private void markKeysAsUsed(Transaction tx) {
|
||||
lock.lock();
|
||||
try {
|
||||
for (TransactionOutput o : tx.getOutputs()) {
|
||||
try {
|
||||
Script script = o.getScriptPubKey();
|
||||
if (script.isSentToRawPubKey()) {
|
||||
byte[] pubkey = script.getPubKey();
|
||||
keychain.markPubKeyAsUsed(pubkey);
|
||||
} else if (script.isSentToAddress()) {
|
||||
byte[] pubkeyHash = script.getPubKeyHash();
|
||||
keychain.markPubKeyHashAsUsed(pubkeyHash);
|
||||
}
|
||||
} catch (ScriptException e) {
|
||||
// Just means we didn't understand the output of this transaction: ignore it.
|
||||
log.warn("Could not parse tx output script: {}", e.toString());
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the immutable seed for the current active HD chain.
|
||||
* @throws com.google.bitcoin.core.ECKey.MissingPrivateKeyException if the seed is unavailable (watching wallet)
|
||||
@ -1230,6 +1257,9 @@ public class Wallet extends BaseTaggableObject implements Serializable, BlockCha
|
||||
bitcoinValueToFriendlyString(valueDifference), tx.getHashAsString(), relativityOffset,
|
||||
block != null ? block.getHeader().getHash() : "(unit test)");
|
||||
|
||||
// mark the deterministic keys in this transaction as used
|
||||
markKeysAsUsed(tx);
|
||||
|
||||
onWalletChangedSuppressions++;
|
||||
|
||||
// If this transaction is already in the wallet we may need to move it into a different pool. At the very
|
||||
|
@ -295,6 +295,28 @@ public class DeterministicKeyChain implements EncryptableKeyChain {
|
||||
basicKeyChain.importKeys(ImmutableList.of(key));
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark the DeterministicKey as used.
|
||||
* Also correct the issued{Internal|External}Keys counter, because all lower children seem to be requested already.
|
||||
* If the counter was updated, we also might want to update the lookahead keys.
|
||||
*/
|
||||
public DeterministicKey markKeyAsUsed(DeterministicKey k) {
|
||||
int numchilds = k.getChildNumber().i() + 1;
|
||||
|
||||
if (k.getParent() == internalKey) {
|
||||
if (issuedInternalKeys < numchilds) {
|
||||
issuedInternalKeys = numchilds;
|
||||
maybeLookAhead();
|
||||
}
|
||||
} else if (k.getParent() == externalKey) {
|
||||
if (issuedExternalKeys < numchilds) {
|
||||
issuedExternalKeys = numchilds;
|
||||
maybeLookAhead();
|
||||
}
|
||||
}
|
||||
return k;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DeterministicKey findKeyFromPubHash(byte[] pubkeyHash) {
|
||||
lock.lock();
|
||||
@ -315,6 +337,38 @@ public class DeterministicKeyChain implements EncryptableKeyChain {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark the DeterministicKeys as used, if they match the pubkeyHash
|
||||
* See {@link com.google.bitcoin.wallet.DeterministicKeyChain#markKeyAsUsed(DeterministicKey)} for more info on this.
|
||||
*/
|
||||
public boolean markPubHashAsUsed(byte[] pubkeyHash) {
|
||||
lock.lock();
|
||||
try {
|
||||
DeterministicKey k = (DeterministicKey) basicKeyChain.findKeyFromPubHash(pubkeyHash);
|
||||
if (k != null)
|
||||
markKeyAsUsed(k);
|
||||
return k != null;
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark the DeterministicKeys as used, if they match the pubkey
|
||||
* See {@link com.google.bitcoin.wallet.DeterministicKeyChain#markKeyAsUsed(DeterministicKey)} for more info on this.
|
||||
*/
|
||||
public boolean markPubKeyAsUsed(byte[] pubkey) {
|
||||
lock.lock();
|
||||
try {
|
||||
DeterministicKey k = (DeterministicKey) basicKeyChain.findKeyFromPubKey(pubkey);
|
||||
if (k != null)
|
||||
markKeyAsUsed(k);
|
||||
return k != null;
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasKey(ECKey key) {
|
||||
lock.lock();
|
||||
|
@ -227,6 +227,18 @@ public class KeyChainGroup {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark the DeterministicKeys as used, if they match the pubkeyHash
|
||||
* See {@link com.google.bitcoin.wallet.DeterministicKeyChain#markKeyAsUsed(DeterministicKey)} for more info on this.
|
||||
*/
|
||||
public void markPubKeyHashAsUsed(byte[] pubkeyHash) {
|
||||
for (DeterministicKeyChain chain : chains) {
|
||||
if (chain.markPubHashAsUsed(pubkeyHash))
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public boolean hasKey(ECKey key) {
|
||||
if (basic.hasKey(key))
|
||||
return true;
|
||||
@ -248,6 +260,17 @@ public class KeyChainGroup {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark the DeterministicKeys as used, if they match the pubkey
|
||||
* See {@link com.google.bitcoin.wallet.DeterministicKeyChain#markKeyAsUsed(DeterministicKey)} for more info on this.
|
||||
*/
|
||||
public void markPubKeyAsUsed(byte[] pubkey) {
|
||||
for (DeterministicKeyChain chain : chains) {
|
||||
if (chain.markPubKeyAsUsed(pubkey))
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns the number of keys managed by this group, including the lookahead buffers. */
|
||||
public int numKeys() {
|
||||
int result = basic.numKeys();
|
||||
|
Loading…
Reference in New Issue
Block a user