handle user defined fee amount better by requiring a fee rate of 1 sat/vb for utxo selectors

This commit is contained in:
Craig Raw 2021-04-26 14:40:11 +02:00
parent b5b384f5da
commit 40faaec31e
3 changed files with 18 additions and 10 deletions

2
drongo

@ -1 +1 @@
Subproject commit db05e09fe54d80d611153cc4326d83cc91359ffa Subproject commit db9617ee10383bb78e71ec2252d92bb7fe639440

View file

@ -219,7 +219,7 @@ public class PaymentController extends WalletFormController implements Initializ
} }
TransactionOutput txOutput = new TransactionOutput(new Transaction(), 1L, address.getOutputScript()); TransactionOutput txOutput = new TransactionOutput(new Transaction(), 1L, address.getOutputScript());
return address.getScriptType().getDustThreshold(txOutput, sendController.getFeeRate()); return address.getScriptType().getDustThreshold(txOutput, Transaction.DUST_RELAY_TX_FEE);
} }
private void setFiatAmount(CurrencyRate currencyRate, Long amount) { private void setFiatAmount(CurrencyRate currencyRate, Long amount) {

View file

@ -342,10 +342,6 @@ public class SendController extends WalletFormController implements Initializabl
if(userFeeSet.get()) { if(userFeeSet.get()) {
setTargetBlocks(getTargetBlocks(feeRate)); setTargetBlocks(getTargetBlocks(feeRate));
setFeeRangeRate(feeRate); setFeeRangeRate(feeRate);
if(walletTransaction.getFee() != getFeeValueSats() && feeRate > getMinimumFeeRate()) {
setFeeValueSats(walletTransaction.getFee());
}
} else { } else {
setFeeValueSats(walletTransaction.getFee()); setFeeValueSats(walletTransaction.getFee());
} }
@ -483,17 +479,18 @@ public class SendController extends WalletFormController implements Initializabl
if(!userFeeSet.get() || (getFeeValueSats() != null && getFeeValueSats() > 0)) { if(!userFeeSet.get() || (getFeeValueSats() != null && getFeeValueSats() > 0)) {
Wallet wallet = getWalletForm().getWallet(); Wallet wallet = getWalletForm().getWallet();
Long userFee = userFeeSet.get() ? getFeeValueSats() : null; Long userFee = userFeeSet.get() ? getFeeValueSats() : null;
double feeRate = getUserFeeRate();
Integer currentBlockHeight = AppServices.getCurrentBlockHeight(); Integer currentBlockHeight = AppServices.getCurrentBlockHeight();
boolean groupByAddress = Config.get().isGroupByAddress(); boolean groupByAddress = Config.get().isGroupByAddress();
boolean includeMempoolOutputs = Config.get().isIncludeMempoolOutputs(); boolean includeMempoolOutputs = Config.get().isIncludeMempoolOutputs();
boolean includeSpentMempoolOutputs = includeSpentMempoolOutputsProperty.get(); boolean includeSpentMempoolOutputs = includeSpentMempoolOutputsProperty.get();
WalletTransaction walletTransaction = wallet.createWalletTransaction(getUtxoSelectors(), getUtxoFilters(), payments, getFeeRate(), getMinimumFeeRate(), userFee, currentBlockHeight, groupByAddress, includeMempoolOutputs, includeSpentMempoolOutputs); WalletTransaction walletTransaction = wallet.createWalletTransaction(getUtxoSelectors(), getUtxoFilters(), payments, feeRate, getMinimumFeeRate(), userFee, currentBlockHeight, groupByAddress, includeMempoolOutputs, includeSpentMempoolOutputs);
walletTransactionProperty.setValue(walletTransaction); walletTransactionProperty.setValue(walletTransaction);
insufficientInputsProperty.set(false); insufficientInputsProperty.set(false);
return; return;
} }
} catch(InvalidAddressException | IllegalStateException e) { } catch(InvalidAddressException | IllegalStateException | IllegalArgumentException e) {
//ignore //ignore
} catch(InsufficientFundsException e) { } catch(InsufficientFundsException e) {
insufficientInputsProperty.set(true); insufficientInputsProperty.set(true);
@ -508,8 +505,8 @@ public class SendController extends WalletFormController implements Initializabl
} }
Wallet wallet = getWalletForm().getWallet(); Wallet wallet = getWalletForm().getWallet();
long noInputsFee = wallet.getNoInputsFee(getPayments(), getFeeRate()); long noInputsFee = wallet.getNoInputsFee(getPayments(), getUserFeeRate());
long costOfChange = wallet.getCostOfChange(getFeeRate(), getMinimumFeeRate()); long costOfChange = wallet.getCostOfChange(getUserFeeRate(), getMinimumFeeRate());
return List.of(new BnBUtxoSelector(noInputsFee, costOfChange), new KnapsackUtxoSelector(noInputsFee)); return List.of(new BnBUtxoSelector(noInputsFee, costOfChange), new KnapsackUtxoSelector(noInputsFee));
} }
@ -619,6 +616,17 @@ public class SendController extends WalletFormController implements Initializabl
feeRange.valueProperty().addListener(feeRangeListener); feeRange.valueProperty().addListener(feeRangeListener);
} }
/**
* This method retrieves the fee rate used as input to constructing the transaction.
* Where the user has set a custom fee amount, using the slider fee rate can mean the UTXO selectors underestimate the UTXO effective values and fail to find a solution
* In this case, use a fee rate of 1 sat/VB for maximum flexibility
*
* @return the fee rate to use when constructing a transaction
*/
public Double getUserFeeRate() {
return (userFeeSet.get() ? Transaction.DEFAULT_MIN_RELAY_FEE : getFeeRate());
}
public Double getFeeRate() { public Double getFeeRate() {
if(targetBlocksField.isVisible()) { if(targetBlocksField.isVisible()) {
return getTargetBlocksFeeRates().get(getTargetBlocks()); return getTargetBlocksFeeRates().get(getTargetBlocks());