From d05ec39df7d7c8d23f61f39338c467b9507f0aaa Mon Sep 17 00:00:00 2001 From: Craig Raw Date: Thu, 7 Jul 2022 11:08:39 +0200 Subject: [PATCH] optimize utxo selection through local variable caching of wallet data reused in computation --- .../sparrowwallet/drongo/wallet/Wallet.java | 22 +++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/sparrowwallet/drongo/wallet/Wallet.java b/src/main/java/com/sparrowwallet/drongo/wallet/Wallet.java index 504c6f2..11c3e08 100644 --- a/src/main/java/com/sparrowwallet/drongo/wallet/Wallet.java +++ b/src/main/java/com/sparrowwallet/drongo/wallet/Wallet.java @@ -1206,14 +1206,15 @@ public class Wallet extends Persistable implements Comparable { private List getGroupedUtxos(List utxoFilters, double feeRate, double longTermFeeRate, boolean groupByAddress, boolean includeSpentMempoolOutputs) { List outputGroups = new ArrayList<>(); Map walletTransactions = getWalletTransactions(); + Map walletTxos = getWalletTxos(); for(KeyPurpose keyPurpose : getWalletKeyPurposes()) { - getGroupedUtxos(outputGroups, getNode(keyPurpose), utxoFilters, walletTransactions, feeRate, longTermFeeRate, groupByAddress, includeSpentMempoolOutputs); + getGroupedUtxos(outputGroups, getNode(keyPurpose), utxoFilters, walletTransactions, walletTxos, feeRate, longTermFeeRate, groupByAddress, includeSpentMempoolOutputs); } for(Wallet childWallet : getChildWallets()) { if(childWallet.isNested()) { for(KeyPurpose keyPurpose : childWallet.getWalletKeyPurposes()) { - childWallet.getGroupedUtxos(outputGroups, childWallet.getNode(keyPurpose), utxoFilters, walletTransactions, feeRate, longTermFeeRate, groupByAddress, includeSpentMempoolOutputs); + childWallet.getGroupedUtxos(outputGroups, childWallet.getNode(keyPurpose), utxoFilters, walletTransactions, walletTxos, feeRate, longTermFeeRate, groupByAddress, includeSpentMempoolOutputs); } } } @@ -1221,7 +1222,8 @@ public class Wallet extends Persistable implements Comparable { return outputGroups; } - private void getGroupedUtxos(List outputGroups, WalletNode purposeNode, List utxoFilters, Map walletTransactions, double feeRate, double longTermFeeRate, boolean groupByAddress, boolean includeSpentMempoolOutputs) { + private void getGroupedUtxos(List outputGroups, WalletNode purposeNode, List utxoFilters, Map walletTransactions, Map walletTxos, double feeRate, double longTermFeeRate, boolean groupByAddress, boolean includeSpentMempoolOutputs) { + int inputWeightUnits = getInputWeightUnits(); for(WalletNode addressNode : purposeNode.getChildren()) { OutputGroup outputGroup = null; for(BlockTransactionHashIndex utxo : addressNode.getUnspentTransactionOutputs(includeSpentMempoolOutputs)) { @@ -1231,11 +1233,11 @@ public class Wallet extends Persistable implements Comparable { } if(outputGroup == null || !groupByAddress) { - outputGroup = new OutputGroup(addressNode.getWallet().getScriptType(), getStoredBlockHeight(), getInputWeightUnits(), feeRate, longTermFeeRate); + outputGroup = new OutputGroup(addressNode.getWallet().getScriptType(), getStoredBlockHeight(), inputWeightUnits, feeRate, longTermFeeRate); outputGroups.add(outputGroup); } - outputGroup.add(utxo, allInputsFromWallet(walletTransactions, utxo.getHash())); + outputGroup.add(utxo, allInputsFromWallet(walletTransactions, walletTxos, utxo.getHash())); } } } @@ -1248,10 +1250,11 @@ public class Wallet extends Persistable implements Comparable { */ public boolean allInputsFromWallet(Sha256Hash txId) { Map allTransactions = getWalletTransactions(); - return allInputsFromWallet(allTransactions, txId); + Map allTxos = getWalletTxos(); + return allInputsFromWallet(allTransactions, allTxos, txId); } - private boolean allInputsFromWallet(Map walletTransactions, Sha256Hash txId) { + private boolean allInputsFromWallet(Map walletTransactions, Map walletTxos, Sha256Hash txId) { BlockTransaction utxoBlkTx = walletTransactions.get(txId); if(utxoBlkTx == null) { //Provided txId was not a wallet transaction @@ -1269,7 +1272,7 @@ public class Wallet extends Persistable implements Comparable { TransactionOutput prevTxOut = prevBlkTx.getTransaction().getOutputs().get(index); BlockTransactionHashIndex spendingTXI = new BlockTransactionHashIndex(utxoBlkTx.getHash(), utxoBlkTx.getHeight(), utxoBlkTx.getDate(), utxoBlkTx.getFee(), i, prevTxOut.getValue()); BlockTransactionHashIndex spentTXO = new BlockTransactionHashIndex(prevBlkTx.getHash(), prevBlkTx.getHeight(), prevBlkTx.getDate(), prevBlkTx.getFee(), index, prevTxOut.getValue(), spendingTXI); - if(!isWalletTxo(spentTXO)) { + if(!walletTxos.containsKey(spentTXO)) { return false; } } @@ -1287,9 +1290,10 @@ public class Wallet extends Persistable implements Comparable { public long getMaxSpendable(List
paymentAddresses, double feeRate, boolean includeSpentMempoolOutputs) { long maxInputValue = 0; + Map cachedInputWeightUnits = new HashMap<>(); Transaction transaction = new Transaction(); for(Map.Entry utxo : getWalletUtxos(includeSpentMempoolOutputs).entrySet()) { - int inputWeightUnits = utxo.getValue().getWallet().getInputWeightUnits(); + int inputWeightUnits = cachedInputWeightUnits.computeIfAbsent(utxo.getValue().getWallet(), Wallet::getInputWeightUnits); long minInputValue = (long)Math.ceil(feeRate * inputWeightUnits / WITNESS_SCALE_FACTOR); if(utxo.getKey().getValue() > minInputValue) { Transaction prevTx = getWalletTransaction(utxo.getKey().getHash()).getTransaction();