|
|
@ -342,71 +342,73 @@ public abstract class Bitcoiny implements ForeignBlockchain { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public List<SimpleTransaction> getWalletTransactions(String key58) throws ForeignBlockchainException { |
|
|
|
public List<SimpleTransaction> getWalletTransactions(String key58) throws ForeignBlockchainException { |
|
|
|
Context.propagate(bitcoinjContext); |
|
|
|
synchronized (this) { |
|
|
|
|
|
|
|
Context.propagate(bitcoinjContext); |
|
|
|
|
|
|
|
|
|
|
|
Wallet wallet = walletFromDeterministicKey58(key58); |
|
|
|
Wallet wallet = walletFromDeterministicKey58(key58); |
|
|
|
DeterministicKeyChain keyChain = wallet.getActiveKeyChain(); |
|
|
|
DeterministicKeyChain keyChain = wallet.getActiveKeyChain(); |
|
|
|
|
|
|
|
|
|
|
|
keyChain.setLookaheadSize(Bitcoiny.WALLET_KEY_LOOKAHEAD_INCREMENT); |
|
|
|
keyChain.setLookaheadSize(Bitcoiny.WALLET_KEY_LOOKAHEAD_INCREMENT); |
|
|
|
keyChain.maybeLookAhead(); |
|
|
|
keyChain.maybeLookAhead(); |
|
|
|
|
|
|
|
|
|
|
|
List<DeterministicKey> keys = new ArrayList<>(keyChain.getLeafKeys()); |
|
|
|
List<DeterministicKey> keys = new ArrayList<>(keyChain.getLeafKeys()); |
|
|
|
|
|
|
|
|
|
|
|
Set<BitcoinyTransaction> walletTransactions = new HashSet<>(); |
|
|
|
Set<BitcoinyTransaction> walletTransactions = new HashSet<>(); |
|
|
|
Set<String> keySet = new HashSet<>(); |
|
|
|
Set<String> keySet = new HashSet<>(); |
|
|
|
|
|
|
|
|
|
|
|
// Set the number of consecutive empty batches required before giving up
|
|
|
|
// Set the number of consecutive empty batches required before giving up
|
|
|
|
final int numberOfAdditionalBatchesToSearch = 5; |
|
|
|
final int numberOfAdditionalBatchesToSearch = 5; |
|
|
|
|
|
|
|
|
|
|
|
int unusedCounter = 0; |
|
|
|
int unusedCounter = 0; |
|
|
|
int ki = 0; |
|
|
|
int ki = 0; |
|
|
|
do { |
|
|
|
do { |
|
|
|
boolean areAllKeysUnused = true; |
|
|
|
boolean areAllKeysUnused = true; |
|
|
|
|
|
|
|
|
|
|
|
for (; ki < keys.size(); ++ki) { |
|
|
|
for (; ki < keys.size(); ++ki) { |
|
|
|
DeterministicKey dKey = keys.get(ki); |
|
|
|
DeterministicKey dKey = keys.get(ki); |
|
|
|
|
|
|
|
|
|
|
|
// Check for transactions
|
|
|
|
// Check for transactions
|
|
|
|
Address address = Address.fromKey(this.params, dKey, ScriptType.P2PKH); |
|
|
|
Address address = Address.fromKey(this.params, dKey, ScriptType.P2PKH); |
|
|
|
keySet.add(address.toString()); |
|
|
|
keySet.add(address.toString()); |
|
|
|
byte[] script = ScriptBuilder.createOutputScript(address).getProgram(); |
|
|
|
byte[] script = ScriptBuilder.createOutputScript(address).getProgram(); |
|
|
|
|
|
|
|
|
|
|
|
// Ask for transaction history - if it's empty then key has never been used
|
|
|
|
// Ask for transaction history - if it's empty then key has never been used
|
|
|
|
List<TransactionHash> historicTransactionHashes = this.blockchain.getAddressTransactions(script, false); |
|
|
|
List<TransactionHash> historicTransactionHashes = this.blockchain.getAddressTransactions(script, false); |
|
|
|
|
|
|
|
|
|
|
|
if (!historicTransactionHashes.isEmpty()) { |
|
|
|
if (!historicTransactionHashes.isEmpty()) { |
|
|
|
areAllKeysUnused = false; |
|
|
|
areAllKeysUnused = false; |
|
|
|
|
|
|
|
|
|
|
|
for (TransactionHash transactionHash : historicTransactionHashes) |
|
|
|
for (TransactionHash transactionHash : historicTransactionHashes) |
|
|
|
walletTransactions.add(this.getTransaction(transactionHash.txHash)); |
|
|
|
walletTransactions.add(this.getTransaction(transactionHash.txHash)); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (areAllKeysUnused) { |
|
|
|
if (areAllKeysUnused) { |
|
|
|
// No transactions
|
|
|
|
// No transactions
|
|
|
|
if (unusedCounter >= numberOfAdditionalBatchesToSearch) { |
|
|
|
if (unusedCounter >= numberOfAdditionalBatchesToSearch) { |
|
|
|
// ... and we've hit our search limit
|
|
|
|
// ... and we've hit our search limit
|
|
|
|
break; |
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
// We haven't hit our search limit yet so increment the counter and keep looking
|
|
|
|
|
|
|
|
unusedCounter++; |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
// Some keys in this batch were used, so reset the counter
|
|
|
|
|
|
|
|
unusedCounter = 0; |
|
|
|
} |
|
|
|
} |
|
|
|
// We haven't hit our search limit yet so increment the counter and keep looking
|
|
|
|
|
|
|
|
unusedCounter++; |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
// Some keys in this batch were used, so reset the counter
|
|
|
|
|
|
|
|
unusedCounter = 0; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Generate some more keys
|
|
|
|
// Generate some more keys
|
|
|
|
keys.addAll(generateMoreKeys(keyChain)); |
|
|
|
keys.addAll(generateMoreKeys(keyChain)); |
|
|
|
|
|
|
|
|
|
|
|
// Process new keys
|
|
|
|
// Process new keys
|
|
|
|
} while (true); |
|
|
|
} while (true); |
|
|
|
|
|
|
|
|
|
|
|
Comparator<SimpleTransaction> newestTimestampFirstComparator = Comparator.comparingInt(SimpleTransaction::getTimestamp).reversed(); |
|
|
|
Comparator<SimpleTransaction> newestTimestampFirstComparator = Comparator.comparingInt(SimpleTransaction::getTimestamp).reversed(); |
|
|
|
|
|
|
|
|
|
|
|
// Update cache and return
|
|
|
|
// Update cache and return
|
|
|
|
return walletTransactions.stream() |
|
|
|
return walletTransactions.stream() |
|
|
|
.map(t -> convertToSimpleTransaction(t, keySet)) |
|
|
|
.map(t -> convertToSimpleTransaction(t, keySet)) |
|
|
|
.sorted(newestTimestampFirstComparator).collect(Collectors.toList()); |
|
|
|
.sorted(newestTimestampFirstComparator).collect(Collectors.toList()); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
protected SimpleTransaction convertToSimpleTransaction(BitcoinyTransaction t, Set<String> keySet) { |
|
|
|
protected SimpleTransaction convertToSimpleTransaction(BitcoinyTransaction t, Set<String> keySet) { |
|
|
|