mirror of
https://github.com/sparrowwallet/sparrow.git
synced 2024-12-25 13:16:44 +00:00
add additional rbf tx inputs if needed as required fee is increased
This commit is contained in:
parent
719cfaa906
commit
f534beb624
3 changed files with 45 additions and 10 deletions
2
drongo
2
drongo
|
@ -1 +1 @@
|
||||||
Subproject commit b26c5e5218b91c760b7f63f47d93b7301223cc2c
|
Subproject commit 5b9b3043a6fded8e6f1589327a9fa2718b41f90c
|
|
@ -245,8 +245,8 @@ public class EntryCell extends TreeTableCell<Entry, Entry> implements Confirmati
|
||||||
double vSize = tx.getVirtualSize();
|
double vSize = tx.getVirtualSize();
|
||||||
int inputSize = tx.getInputs().get(0).getLength() + (tx.getInputs().get(0).hasWitness() ? tx.getInputs().get(0).getWitness().getLength() / Transaction.WITNESS_SCALE_FACTOR : 0);
|
int inputSize = tx.getInputs().get(0).getLength() + (tx.getInputs().get(0).hasWitness() ? tx.getInputs().get(0).getWitness().getLength() / Transaction.WITNESS_SCALE_FACTOR : 0);
|
||||||
List<BlockTransactionHashIndex> walletUtxos = new ArrayList<>(transactionEntry.getWallet().getWalletUtxos().keySet());
|
List<BlockTransactionHashIndex> walletUtxos = new ArrayList<>(transactionEntry.getWallet().getWalletUtxos().keySet());
|
||||||
//Remove any UTXOs created by the transaction that is to be replaced
|
//Remove any UTXOs that are frozen or created by the transaction that is to be replaced
|
||||||
walletUtxos.removeIf(utxo -> ourOutputs.stream().anyMatch(output -> output.getHash().equals(utxo.getHash()) && output.getIndex() == utxo.getIndex()));
|
walletUtxos.removeIf(utxo -> utxo.getStatus() == Status.FROZEN || ourOutputs.stream().anyMatch(output -> output.getHash().equals(utxo.getHash()) && output.getIndex() == utxo.getIndex()));
|
||||||
Collections.shuffle(walletUtxos);
|
Collections.shuffle(walletUtxos);
|
||||||
while((double)changeTotal / vSize < getMaxFeeRate() && !walletUtxos.isEmpty() && !cancelTransaction) {
|
while((double)changeTotal / vSize < getMaxFeeRate() && !walletUtxos.isEmpty() && !cancelTransaction) {
|
||||||
//If there is insufficient change output, include another random UTXO so the fee can be increased
|
//If there is insufficient change output, include another random UTXO so the fee can be increased
|
||||||
|
|
|
@ -697,6 +697,41 @@ public class SendController extends WalletFormController implements Initializabl
|
||||||
protected Task<WalletTransaction> createTask() {
|
protected Task<WalletTransaction> createTask() {
|
||||||
return new Task<>() {
|
return new Task<>() {
|
||||||
protected WalletTransaction call() throws InsufficientFundsException {
|
protected WalletTransaction call() throws InsufficientFundsException {
|
||||||
|
try {
|
||||||
|
return getWalletTransaction();
|
||||||
|
} catch(InsufficientFundsException e) {
|
||||||
|
if(e.getTargetValue() != null && includeSpentMempoolOutputs && utxoSelectors.size() == 1 && utxoSelectors.get(0) instanceof PresetUtxoSelector presetUtxoSelector) {
|
||||||
|
Optional<BlockTransaction> optBlkTx = wallet.getWalletTransactions().values().stream().filter(blkTx -> {
|
||||||
|
return blkTx.getTransaction().getInputs().stream().anyMatch(txInput -> {
|
||||||
|
return presetUtxoSelector.getPresetUtxos().stream().anyMatch(ref -> {
|
||||||
|
return txInput.getOutpoint().getHash().equals(ref.getHash()) && txInput.getOutpoint().getIndex() == ref.getIndex();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}).findFirst();
|
||||||
|
|
||||||
|
if(optBlkTx.isPresent()) {
|
||||||
|
//Creating RBF transaction - include additional UTXOs if available to pay desired fee
|
||||||
|
Transaction rbfTx = optBlkTx.get().getTransaction();
|
||||||
|
List<BlockTransactionHashIndex> walletUtxos = new ArrayList<>(wallet.getWalletUtxos().keySet());
|
||||||
|
//Remove any UTXOs that are frozen or created by the transaction that is to be replaced
|
||||||
|
walletUtxos.removeIf(utxo -> utxo.getStatus() == Status.FROZEN || rbfTx.getOutputs().stream().anyMatch(output -> output.getHash().equals(utxo.getHash()) && output.getIndex() == utxo.getIndex()));
|
||||||
|
//Remove any UTXOs that have already been added or previously excluded
|
||||||
|
walletUtxos.removeAll(presetUtxoSelector.getPresetUtxos());
|
||||||
|
walletUtxos.removeAll(presetUtxoSelector.getExcludedUtxos());
|
||||||
|
Collections.shuffle(walletUtxos);
|
||||||
|
while(!walletUtxos.isEmpty() && presetUtxoSelector.getPresetUtxos().stream().mapToLong(BlockTransactionHashIndex::getValue).sum() < e.getTargetValue()) {
|
||||||
|
presetUtxoSelector.getPresetUtxos().add(walletUtxos.remove(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
return getWalletTransaction();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private WalletTransaction getWalletTransaction() throws InsufficientFundsException {
|
||||||
updateMessage("Selecting UTXOs...");
|
updateMessage("Selecting UTXOs...");
|
||||||
WalletTransaction walletTransaction = wallet.createWalletTransaction(utxoSelectors, utxoFilters, payments, opReturns, excludedChangeNodes,
|
WalletTransaction walletTransaction = wallet.createWalletTransaction(utxoSelectors, utxoFilters, payments, opReturns, excludedChangeNodes,
|
||||||
feeRate, longTermFeeRate, fee, currentBlockHeight, groupByAddress, includeMempoolOutputs, includeSpentMempoolOutputs);
|
feeRate, longTermFeeRate, fee, currentBlockHeight, groupByAddress, includeMempoolOutputs, includeSpentMempoolOutputs);
|
||||||
|
@ -1589,22 +1624,22 @@ public class SendController extends WalletFormController implements Initializabl
|
||||||
if(utxoSelector instanceof MaxUtxoSelector) {
|
if(utxoSelector instanceof MaxUtxoSelector) {
|
||||||
Collection<BlockTransactionHashIndex> utxos = walletForm.getWallet().getWalletUtxos().keySet();
|
Collection<BlockTransactionHashIndex> utxos = walletForm.getWallet().getWalletUtxos().keySet();
|
||||||
utxos.remove(event.getUtxo());
|
utxos.remove(event.getUtxo());
|
||||||
if(utxoFilterProperty.get() instanceof ExcludeUtxoFilter) {
|
if(utxoFilterProperty.get() instanceof ExcludeUtxoFilter existingUtxoFilter) {
|
||||||
ExcludeUtxoFilter existingUtxoFilter = (ExcludeUtxoFilter)utxoFilterProperty.get();
|
|
||||||
utxos.removeAll(existingUtxoFilter.getExcludedUtxos());
|
utxos.removeAll(existingUtxoFilter.getExcludedUtxos());
|
||||||
}
|
}
|
||||||
PresetUtxoSelector presetUtxoSelector = new PresetUtxoSelector(utxos);
|
PresetUtxoSelector presetUtxoSelector = new PresetUtxoSelector(utxos);
|
||||||
|
presetUtxoSelector.getExcludedUtxos().add(event.getUtxo());
|
||||||
utxoSelectorProperty.set(presetUtxoSelector);
|
utxoSelectorProperty.set(presetUtxoSelector);
|
||||||
updateTransaction(true);
|
updateTransaction(true);
|
||||||
} else if(utxoSelector instanceof PresetUtxoSelector) {
|
} else if(utxoSelector instanceof PresetUtxoSelector existingUtxoSelector) {
|
||||||
PresetUtxoSelector presetUtxoSelector = new PresetUtxoSelector(((PresetUtxoSelector)utxoSelector).getPresetUtxos());
|
PresetUtxoSelector presetUtxoSelector = new PresetUtxoSelector(existingUtxoSelector.getPresetUtxos(), existingUtxoSelector.getExcludedUtxos());
|
||||||
presetUtxoSelector.getPresetUtxos().remove(event.getUtxo());
|
presetUtxoSelector.getPresetUtxos().remove(event.getUtxo());
|
||||||
|
presetUtxoSelector.getExcludedUtxos().add(event.getUtxo());
|
||||||
utxoSelectorProperty.set(presetUtxoSelector);
|
utxoSelectorProperty.set(presetUtxoSelector);
|
||||||
updateTransaction(true);
|
updateTransaction(!includeSpentMempoolOutputsProperty.get());
|
||||||
} else {
|
} else {
|
||||||
ExcludeUtxoFilter utxoFilter = new ExcludeUtxoFilter();
|
ExcludeUtxoFilter utxoFilter = new ExcludeUtxoFilter();
|
||||||
if(utxoFilterProperty.get() instanceof ExcludeUtxoFilter) {
|
if(utxoFilterProperty.get() instanceof ExcludeUtxoFilter existingUtxoFilter) {
|
||||||
ExcludeUtxoFilter existingUtxoFilter = (ExcludeUtxoFilter)utxoFilterProperty.get();
|
|
||||||
utxoFilter.getExcludedUtxos().addAll(existingUtxoFilter.getExcludedUtxos());
|
utxoFilter.getExcludedUtxos().addAll(existingUtxoFilter.getExcludedUtxos());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue