diff --git a/src/main/java/com/sparrowwallet/drongo/wallet/Wallet.java b/src/main/java/com/sparrowwallet/drongo/wallet/Wallet.java index 777e2e5..8cf5d2e 100644 --- a/src/main/java/com/sparrowwallet/drongo/wallet/Wallet.java +++ b/src/main/java/com/sparrowwallet/drongo/wallet/Wallet.java @@ -313,15 +313,19 @@ public class Wallet { } public Map getWalletUtxos() { + return getWalletUtxos(false); + } + + public Map getWalletUtxos(boolean includeMempoolInputs) { Map walletUtxos = new TreeMap<>(); - getWalletUtxos(walletUtxos, getNode(KeyPurpose.RECEIVE)); - getWalletUtxos(walletUtxos, getNode(KeyPurpose.CHANGE)); + getWalletUtxos(walletUtxos, getNode(KeyPurpose.RECEIVE), includeMempoolInputs); + getWalletUtxos(walletUtxos, getNode(KeyPurpose.CHANGE), includeMempoolInputs); return walletUtxos; } - private void getWalletUtxos(Map walletUtxos, WalletNode purposeNode) { + private void getWalletUtxos(Map walletUtxos, WalletNode purposeNode, boolean includeMempoolInputs) { for(WalletNode addressNode : purposeNode.getChildren()) { - for(BlockTransactionHashIndex utxo : addressNode.getUnspentTransactionOutputs()) { + for(BlockTransactionHashIndex utxo : addressNode.getUnspentTransactionOutputs(includeMempoolInputs)) { walletUtxos.put(utxo, addressNode); } } @@ -436,12 +440,12 @@ public class Wallet { return getFee(changeOutput, feeRate, longTermFeeRate); } - public WalletTransaction createWalletTransaction(List utxoSelectors, List utxoFilters, List payments, double feeRate, double longTermFeeRate, Long fee, Integer currentBlockHeight, boolean groupByAddress, boolean includeMempoolChange) throws InsufficientFundsException { + public WalletTransaction createWalletTransaction(List utxoSelectors, List utxoFilters, List payments, double feeRate, double longTermFeeRate, Long fee, Integer currentBlockHeight, boolean groupByAddress, boolean includeMempoolChange, boolean includeMempoolInputs) throws InsufficientFundsException { long totalPaymentAmount = payments.stream().map(Payment::getAmount).mapToLong(v -> v).sum(); long valueRequiredAmt = totalPaymentAmount; while(true) { - Map selectedUtxos = selectInputs(utxoSelectors, utxoFilters, valueRequiredAmt, feeRate, longTermFeeRate, groupByAddress, includeMempoolChange); + Map selectedUtxos = selectInputs(utxoSelectors, utxoFilters, valueRequiredAmt, feeRate, longTermFeeRate, groupByAddress, includeMempoolChange, includeMempoolInputs); long totalSelectedAmt = selectedUtxos.keySet().stream().mapToLong(BlockTransactionHashIndex::getValue).sum(); Transaction transaction = new Transaction(); @@ -539,8 +543,8 @@ public class Wallet { } } - private Map selectInputs(List utxoSelectors, List utxoFilters, Long targetValue, double feeRate, double longTermFeeRate, boolean groupByAddress, boolean includeMempoolChange) throws InsufficientFundsException { - List utxoPool = getGroupedUtxos(utxoFilters, feeRate, longTermFeeRate, groupByAddress); + private Map selectInputs(List utxoSelectors, List utxoFilters, Long targetValue, double feeRate, double longTermFeeRate, boolean groupByAddress, boolean includeMempoolChange, boolean includeMempoolInputs) throws InsufficientFundsException { + List utxoPool = getGroupedUtxos(utxoFilters, feeRate, longTermFeeRate, groupByAddress, includeMempoolInputs); List filters = new ArrayList<>(); filters.add(new OutputGroup.Filter(1, 6)); @@ -556,7 +560,7 @@ public class Wallet { Collection selectedInputs = utxoSelector.select(targetValue, filteredPool); long total = selectedInputs.stream().mapToLong(BlockTransactionHashIndex::getValue).sum(); if(total > targetValue) { - Map utxos = getWalletUtxos(); + Map utxos = getWalletUtxos(includeMempoolInputs); utxos.keySet().retainAll(selectedInputs); return utxos; } @@ -566,17 +570,17 @@ public class Wallet { throw new InsufficientFundsException("Not enough combined value in UTXOs for output value " + targetValue); } - private List getGroupedUtxos(List utxoFilters, double feeRate, double longTermFeeRate, boolean groupByAddress) { + private List getGroupedUtxos(List utxoFilters, double feeRate, double longTermFeeRate, boolean groupByAddress, boolean includeMempoolInputs) { List outputGroups = new ArrayList<>(); - getGroupedUtxos(outputGroups, getNode(KeyPurpose.RECEIVE), utxoFilters, feeRate, longTermFeeRate, groupByAddress); - getGroupedUtxos(outputGroups, getNode(KeyPurpose.CHANGE), utxoFilters, feeRate, longTermFeeRate, groupByAddress); + getGroupedUtxos(outputGroups, getNode(KeyPurpose.RECEIVE), utxoFilters, feeRate, longTermFeeRate, groupByAddress, includeMempoolInputs); + getGroupedUtxos(outputGroups, getNode(KeyPurpose.CHANGE), utxoFilters, feeRate, longTermFeeRate, groupByAddress, includeMempoolInputs); return outputGroups; } - private void getGroupedUtxos(List outputGroups, WalletNode purposeNode, List utxoFilters, double feeRate, double longTermFeeRate, boolean groupByAddress) { + private void getGroupedUtxos(List outputGroups, WalletNode purposeNode, List utxoFilters, double feeRate, double longTermFeeRate, boolean groupByAddress, boolean includeMempoolInputs) { for(WalletNode addressNode : purposeNode.getChildren()) { OutputGroup outputGroup = null; - for(BlockTransactionHashIndex utxo : addressNode.getUnspentTransactionOutputs()) { + for(BlockTransactionHashIndex utxo : addressNode.getUnspentTransactionOutputs(includeMempoolInputs)) { Optional matchedFilter = utxoFilters.stream().filter(utxoFilter -> !utxoFilter.isEligible(utxo)).findAny(); if(matchedFilter.isPresent()) { continue; diff --git a/src/main/java/com/sparrowwallet/drongo/wallet/WalletNode.java b/src/main/java/com/sparrowwallet/drongo/wallet/WalletNode.java index 60f749a..0725a68 100644 --- a/src/main/java/com/sparrowwallet/drongo/wallet/WalletNode.java +++ b/src/main/java/com/sparrowwallet/drongo/wallet/WalletNode.java @@ -113,8 +113,12 @@ public class WalletNode implements Comparable { } public Set getUnspentTransactionOutputs() { + return getUnspentTransactionOutputs(false); + } + + public Set getUnspentTransactionOutputs(boolean includeMempoolInputs) { Set unspentTXOs = new TreeSet<>(transactionOutputs); - return unspentTXOs.stream().filter(txo -> !txo.isSpent()).collect(Collectors.toCollection(HashSet::new)); + return unspentTXOs.stream().filter(txo -> !txo.isSpent() || (includeMempoolInputs && txo.getSpentBy().getHeight() <= 0)).collect(Collectors.toCollection(HashSet::new)); } public long getUnspentValue() {