mirror of
https://github.com/Qortal/qortal.git
synced 2025-02-12 02:05:50 +00:00
Practically rewrote the get unused receive address functionality. The prior implementation was skipping addresses.
This commit is contained in:
parent
46a9075faf
commit
423a1f7bed
@ -11,6 +11,7 @@ import org.bitcoinj.crypto.DeterministicKey;
|
|||||||
import org.bitcoinj.script.Script.ScriptType;
|
import org.bitcoinj.script.Script.ScriptType;
|
||||||
import org.bitcoinj.script.ScriptBuilder;
|
import org.bitcoinj.script.ScriptBuilder;
|
||||||
import org.bitcoinj.wallet.DeterministicKeyChain;
|
import org.bitcoinj.wallet.DeterministicKeyChain;
|
||||||
|
import org.bitcoinj.wallet.KeyChain;
|
||||||
import org.bitcoinj.wallet.SendRequest;
|
import org.bitcoinj.wallet.SendRequest;
|
||||||
import org.bitcoinj.wallet.Wallet;
|
import org.bitcoinj.wallet.Wallet;
|
||||||
import org.qortal.api.model.SimpleForeignTransaction;
|
import org.qortal.api.model.SimpleForeignTransaction;
|
||||||
@ -720,7 +721,7 @@ public abstract class Bitcoiny implements ForeignBlockchain {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns first unused receive address given 'm' BIP32 key.
|
* Returns first unused receive address given a BIP32 key.
|
||||||
*
|
*
|
||||||
* @param key58 BIP32/HD extended Bitcoin private/public key
|
* @param key58 BIP32/HD extended Bitcoin private/public key
|
||||||
* @return P2PKH address
|
* @return P2PKH address
|
||||||
@ -732,65 +733,15 @@ public abstract class Bitcoiny implements ForeignBlockchain {
|
|||||||
Wallet wallet = walletFromDeterministicKey58(key58);
|
Wallet wallet = walletFromDeterministicKey58(key58);
|
||||||
DeterministicKeyChain keyChain = wallet.getActiveKeyChain();
|
DeterministicKeyChain keyChain = wallet.getActiveKeyChain();
|
||||||
|
|
||||||
keyChain.setLookaheadSize(Bitcoiny.WALLET_KEY_LOOKAHEAD_INCREMENT);
|
|
||||||
keyChain.maybeLookAhead();
|
|
||||||
|
|
||||||
final int keyChainPathSize = keyChain.getAccountPath().size();
|
|
||||||
List<DeterministicKey> keys = new ArrayList<>(keyChain.getLeafKeys());
|
|
||||||
|
|
||||||
int ki = 0;
|
|
||||||
do {
|
do {
|
||||||
for (; ki < keys.size(); ++ki) {
|
// the next receive funds address
|
||||||
DeterministicKey dKey = keys.get(ki);
|
Address address = Address.fromKey(this.params, keyChain.getKey(KeyChain.KeyPurpose.RECEIVE_FUNDS), ScriptType.P2PKH);
|
||||||
List<ChildNumber> dKeyPath = dKey.getPath();
|
|
||||||
|
|
||||||
// If keyChain is based on 'm', then make sure dKey is m/0/ki - i.e. a 'receive' address, not 'change' (m/1/ki)
|
// if zero transactions, return address
|
||||||
if (dKeyPath.size() != keyChainPathSize + 2 || dKeyPath.get(dKeyPath.size() - 2) != ChildNumber.ZERO)
|
if( 0 == getAddressTransactions(ScriptBuilder.createOutputScript(address).getProgram(), true).size() )
|
||||||
continue;
|
return address.toString();
|
||||||
|
|
||||||
// Check unspent
|
// else try the next receive funds address
|
||||||
Address address = Address.fromKey(this.params, dKey, ScriptType.P2PKH);
|
|
||||||
byte[] script = ScriptBuilder.createOutputScript(address).getProgram();
|
|
||||||
|
|
||||||
List<UnspentOutput> unspentOutputs = this.blockchainProvider.getUnspentOutputs(script, false);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* If there are no unspent outputs then either:
|
|
||||||
* a) all the outputs have been spent
|
|
||||||
* b) address has never been used
|
|
||||||
*
|
|
||||||
* For case (a) we want to remember not to check this address (key) again.
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (unspentOutputs.isEmpty()) {
|
|
||||||
// If this is a known key that has been spent before, then we can skip asking for transaction history
|
|
||||||
if (this.spentKeys.contains(dKey)) {
|
|
||||||
wallet.getActiveKeyChain().markKeyAsUsed(dKey);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ask for transaction history - if it's empty then key has never been used
|
|
||||||
List<TransactionHash> historicTransactionHashes = this.blockchainProvider.getAddressTransactions(script, false);
|
|
||||||
|
|
||||||
if (!historicTransactionHashes.isEmpty()) {
|
|
||||||
// Fully spent key - case (a)
|
|
||||||
this.spentKeys.add(dKey);
|
|
||||||
wallet.getActiveKeyChain().markKeyAsUsed(dKey);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Key never been used - case (b)
|
|
||||||
return address.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Key has unspent outputs, hence used, so no good to us
|
|
||||||
this.spentKeys.remove(dKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generate some more keys
|
|
||||||
keys.addAll(generateMoreKeys(keyChain));
|
|
||||||
|
|
||||||
// Process new keys
|
|
||||||
} while (true);
|
} while (true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user