@@ -2600,8 +2600,12 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletT
2600
2600
2601
2601
scriptChange = GetScriptForDestination (vchPubKey.GetID ());
2602
2602
}
2603
+ CTxOut change_prototype_txout (0 , scriptChange);
2604
+ size_t change_prototype_size = GetSerializeSize (change_prototype_txout, SER_DISK, 0 );
2603
2605
2604
2606
nFeeRet = 0 ;
2607
+ bool pick_new_inputs = true ;
2608
+ CAmount nValueIn = 0 ;
2605
2609
// Start with no fee and loop until there is enough fee
2606
2610
while (true )
2607
2611
{
@@ -2647,15 +2651,18 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletT
2647
2651
}
2648
2652
2649
2653
// Choose coins to use
2650
- CAmount nValueIn = 0 ;
2651
- setCoins.clear ();
2652
- if (!SelectCoins (vAvailableCoins, nValueToSelect, setCoins, nValueIn, coinControl))
2653
- {
2654
- strFailReason = _ (" Insufficient funds" );
2655
- return false ;
2654
+ if (pick_new_inputs) {
2655
+ nValueIn = 0 ;
2656
+ setCoins.clear ();
2657
+ if (!SelectCoins (vAvailableCoins, nValueToSelect, setCoins, nValueIn, coinControl))
2658
+ {
2659
+ strFailReason = _ (" Insufficient funds" );
2660
+ return false ;
2661
+ }
2656
2662
}
2657
2663
2658
2664
const CAmount nChange = nValueIn - nValueToSelect;
2665
+
2659
2666
if (nChange > 0 )
2660
2667
{
2661
2668
// Fill a vout to ourself
@@ -2739,16 +2746,30 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletT
2739
2746
}
2740
2747
2741
2748
if (nFeeRet >= nFeeNeeded) {
2742
- // Reduce fee to only the needed amount if we have change
2743
- // output to increase. This prevents potential overpayment
2744
- // in fees if the coins selected to meet nFeeNeeded result
2745
- // in a transaction that requires less fee than the prior
2746
- // iteration.
2749
+ // Reduce fee to only the needed amount if possible. This
2750
+ // prevents potential overpayment in fees if the coins
2751
+ // selected to meet nFeeNeeded result in a transaction that
2752
+ // requires less fee than the prior iteration.
2753
+
2747
2754
// TODO: The case where nSubtractFeeFromAmount > 0 remains
2748
2755
// to be addressed because it requires returning the fee to
2749
2756
// the payees and not the change output.
2750
- // TODO: The case where there is no change output remains
2751
- // to be addressed so we avoid creating too small an output.
2757
+
2758
+ // If we have no change and a big enough excess fee, then
2759
+ // try to construct transaction again only without picking
2760
+ // new inputs. We now know we only need the smaller fee
2761
+ // (because of reduced tx size) and so we should add a
2762
+ // change output. Only try this once.
2763
+ CAmount fee_needed_for_change = GetMinimumFee (change_prototype_size, currentConfirmationTarget, ::mempool, ::feeEstimator, nullptr , false /* ignoreGlobalPayTxFee */ , conservative_estimate);
2764
+ CAmount minimum_value_for_change = GetDustThreshold (change_prototype_txout, ::dustRelayFee);
2765
+ CAmount max_excess_fee = fee_needed_for_change + minimum_value_for_change;
2766
+ if (nFeeRet > nFeeNeeded + max_excess_fee && nChangePosInOut == -1 && nSubtractFeeFromAmount == 0 && pick_new_inputs) {
2767
+ pick_new_inputs = false ;
2768
+ nFeeRet = nFeeNeeded + fee_needed_for_change;
2769
+ continue ;
2770
+ }
2771
+
2772
+ // If we have change output already, just increase it
2752
2773
if (nFeeRet > nFeeNeeded && nChangePosInOut != -1 && nSubtractFeeFromAmount == 0 ) {
2753
2774
CAmount extraFeePaid = nFeeRet - nFeeNeeded;
2754
2775
std::vector<CTxOut>::iterator change_position = txNew.vout .begin ()+nChangePosInOut;
@@ -2757,6 +2778,12 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletT
2757
2778
}
2758
2779
break ; // Done, enough fee included.
2759
2780
}
2781
+ else if (!pick_new_inputs) {
2782
+ // This shouldn't happen, we should have had enough excess
2783
+ // fee to pay for the new output and still meet nFeeNeeded
2784
+ strFailReason = _ (" Transaction fee and change calculation failed" );
2785
+ return false ;
2786
+ }
2760
2787
2761
2788
// Try to reduce change to include necessary fee
2762
2789
if (nChangePosInOut != -1 && nSubtractFeeFromAmount == 0 ) {
0 commit comments