From 423a1f7bed5fd44e736f47d31ce05e91f17ca173 Mon Sep 17 00:00:00 2001 From: kennycud Date: Fri, 22 Dec 2023 13:22:26 -0800 Subject: [PATCH] Practically rewrote the get unused receive address functionality. The prior implementation was skipping addresses. --- .../java/org/qortal/crosschain/Bitcoiny.java | 65 +++---------------- 1 file changed, 8 insertions(+), 57 deletions(-) diff --git a/src/main/java/org/qortal/crosschain/Bitcoiny.java b/src/main/java/org/qortal/crosschain/Bitcoiny.java index 1749cee93..d52043bb5 100644 --- a/src/main/java/org/qortal/crosschain/Bitcoiny.java +++ b/src/main/java/org/qortal/crosschain/Bitcoiny.java @@ -11,6 +11,7 @@ import org.bitcoinj.script.Script.ScriptType; import org.bitcoinj.script.ScriptBuilder; import org.bitcoinj.wallet.DeterministicKeyChain; +import org.bitcoinj.wallet.KeyChain; import org.bitcoinj.wallet.SendRequest; import org.bitcoinj.wallet.Wallet; import org.qortal.api.model.SimpleForeignTransaction; @@ -720,7 +721,7 @@ else if (!transactionInvolvesExternalWallet) { } /** - * 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 * @return P2PKH address @@ -732,65 +733,15 @@ public String getUnusedReceiveAddress(String key58) throws ForeignBlockchainExce Wallet wallet = walletFromDeterministicKey58(key58); DeterministicKeyChain keyChain = wallet.getActiveKeyChain(); - keyChain.setLookaheadSize(Bitcoiny.WALLET_KEY_LOOKAHEAD_INCREMENT); - keyChain.maybeLookAhead(); - - final int keyChainPathSize = keyChain.getAccountPath().size(); - List keys = new ArrayList<>(keyChain.getLeafKeys()); - - int ki = 0; do { - for (; ki < keys.size(); ++ki) { - DeterministicKey dKey = keys.get(ki); - List 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 (dKeyPath.size() != keyChainPathSize + 2 || dKeyPath.get(dKeyPath.size() - 2) != ChildNumber.ZERO) - continue; - - // Check unspent - Address address = Address.fromKey(this.params, dKey, ScriptType.P2PKH); - byte[] script = ScriptBuilder.createOutputScript(address).getProgram(); - - List 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 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); - } + // the next receive funds address + Address address = Address.fromKey(this.params, keyChain.getKey(KeyChain.KeyPurpose.RECEIVE_FUNDS), ScriptType.P2PKH); - // Generate some more keys - keys.addAll(generateMoreKeys(keyChain)); + // if zero transactions, return address + if( 0 == getAddressTransactions(ScriptBuilder.createOutputScript(address).getProgram(), true).size() ) + return address.toString(); - // Process new keys + // else try the next receive funds address } while (true); }