@@ -2834,7 +2834,6 @@ bool CWallet::CreateTransactionInternal(
2834
2834
2835
2835
CMutableTransaction txNew;
2836
2836
FeeCalculation feeCalc;
2837
- CAmount nFeeNeeded;
2838
2837
std::pair<int64_t , int64_t > tx_sizes;
2839
2838
int nBytes;
2840
2839
{
@@ -2919,7 +2918,6 @@ bool CWallet::CreateTransactionInternal(
2919
2918
coin_selection_params.m_cost_of_change = coin_selection_params.m_discard_feerate .GetFee (coin_selection_params.change_spend_size ) + coin_selection_params.m_change_fee ;
2920
2919
2921
2920
nFeeRet = 0 ;
2922
- bool pick_new_inputs = true ;
2923
2921
CAmount nValueIn = 0 ;
2924
2922
2925
2923
// BnB selector is the only selector used when this is true.
@@ -2932,7 +2930,6 @@ bool CWallet::CreateTransactionInternal(
2932
2930
nChangePosInOut = nChangePosRequest;
2933
2931
txNew.vin .clear ();
2934
2932
txNew.vout .clear ();
2935
- bool fFirst = true ;
2936
2933
2937
2934
CAmount nValueToSelect = nValue;
2938
2935
if (nSubtractFeeFromAmount == 0 )
@@ -2946,169 +2943,136 @@ bool CWallet::CreateTransactionInternal(
2946
2943
{
2947
2944
CTxOut txout (recipient.nAmount , recipient.scriptPubKey );
2948
2945
2949
- if (recipient.fSubtractFeeFromAmount )
2950
- {
2951
- assert (nSubtractFeeFromAmount != 0 );
2952
- txout.nValue -= nFeeRet / nSubtractFeeFromAmount; // Subtract fee equally from each selected recipient
2953
-
2954
- if (fFirst ) // first receiver pays the remainder not divisible by output count
2955
- {
2956
- fFirst = false ;
2957
- txout.nValue -= nFeeRet % nSubtractFeeFromAmount;
2958
- }
2959
- }
2960
- // Include the fee cost for outputs. Note this is only used for BnB right now
2946
+ // Include the fee cost for outputs.
2961
2947
if (!coin_selection_params.m_subtract_fee_outputs ) {
2962
2948
coin_selection_params.tx_noinputs_size += ::GetSerializeSize (txout, PROTOCOL_VERSION);
2963
2949
}
2964
2950
2965
2951
if (IsDust (txout, chain ().relayDustFee ()))
2966
2952
{
2967
- if (recipient.fSubtractFeeFromAmount && nFeeRet > 0 )
2968
- {
2969
- if (txout.nValue < 0 )
2970
- error = _ (" The transaction amount is too small to pay the fee" );
2971
- else
2972
- error = _ (" The transaction amount is too small to send after the fee has been deducted" );
2973
- }
2974
- else
2975
- error = _ (" Transaction amount too small" );
2953
+ error = _ (" Transaction amount too small" );
2976
2954
return false ;
2977
2955
}
2978
2956
txNew.vout .push_back (txout);
2979
2957
}
2980
2958
2981
2959
// Choose coins to use
2982
2960
bool bnb_used = false ;
2983
- if (pick_new_inputs) {
2984
- nValueIn = 0 ;
2985
- setCoins.clear ();
2986
- if (!SelectCoins (vAvailableCoins, nValueToSelect, setCoins, nValueIn, coin_control, coin_selection_params, bnb_used))
2987
- {
2988
- // If BnB was used, it was the first pass. No longer the first pass and continue loop with knapsack.
2989
- if (bnb_used) {
2990
- coin_selection_params.use_bnb = false ;
2991
- continue ;
2992
- }
2993
- else {
2994
- error = _ (" Insufficient funds" );
2995
- return false ;
2996
- }
2961
+ nValueIn = 0 ;
2962
+ setCoins.clear ();
2963
+ if (!SelectCoins (vAvailableCoins, nValueToSelect, setCoins, nValueIn, coin_control, coin_selection_params, bnb_used))
2964
+ {
2965
+ // If BnB was used, it was the first pass. No longer the first pass and continue loop with knapsack.
2966
+ if (bnb_used) {
2967
+ coin_selection_params.use_bnb = false ;
2968
+ continue ;
2969
+ }
2970
+ else {
2971
+ error = _ (" Insufficient funds" );
2972
+ return false ;
2997
2973
}
2998
- } else {
2999
- bnb_used = false ;
3000
2974
}
3001
2975
3002
- const CAmount change_and_fee = nValueIn - nValueToSelect;
3003
- if (change_and_fee > 0 )
3004
- {
3005
- // Fill a vout to ourself
3006
- CTxOut newTxOut (change_and_fee, scriptChange);
3007
-
3008
- // Never create dust outputs; if we would, just
3009
- // add the dust to the fee.
3010
- // The change_and_fee when BnB is used is always going to go to fees.
3011
- if (IsDust (newTxOut, coin_selection_params.m_discard_feerate ) || bnb_used)
3012
- {
3013
- nChangePosInOut = -1 ;
3014
- nFeeRet += change_and_fee;
3015
- }
3016
- else
3017
- {
3018
- if (nChangePosInOut == -1 )
3019
- {
3020
- // Insert change txn at random position:
3021
- nChangePosInOut = GetRandInt (txNew.vout .size ()+1 );
3022
- }
3023
- else if ((unsigned int )nChangePosInOut > txNew.vout .size ())
3024
- {
3025
- error = _ (" Change index out of range" );
3026
- return false ;
3027
- }
2976
+ // Always make a change output
2977
+ // We will reduce the fee from this change output later, and remove the output if it is too small.
2978
+ const CAmount change_and_fee = nValueIn - nValue;
2979
+ assert (change_and_fee >= 0 );
2980
+ CTxOut newTxOut (change_and_fee, scriptChange);
3028
2981
3029
- std::vector<CTxOut>::iterator position = txNew.vout .begin ()+nChangePosInOut;
3030
- txNew.vout .insert (position, newTxOut);
3031
- }
3032
- } else {
3033
- nChangePosInOut = -1 ;
2982
+ if (nChangePosInOut == -1 )
2983
+ {
2984
+ // Insert change txn at random position:
2985
+ nChangePosInOut = GetRandInt (txNew.vout .size ()+1 );
3034
2986
}
2987
+ else if ((unsigned int )nChangePosInOut > txNew.vout .size ())
2988
+ {
2989
+ error = _ (" Change index out of range" );
2990
+ return false ;
2991
+ }
2992
+
2993
+ assert (nChangePosInOut != -1 );
2994
+ auto change_position = txNew.vout .insert (txNew.vout .begin () + nChangePosInOut, newTxOut);
3035
2995
3036
2996
// Dummy fill vin for maximum size estimation
3037
2997
//
3038
2998
for (const auto & coin : setCoins) {
3039
2999
txNew.vin .push_back (CTxIn (coin.outpoint ,CScript ()));
3040
3000
}
3041
3001
3002
+ // Calculate the transaction fee
3042
3003
tx_sizes = CalculateMaximumSignedTxSize (CTransaction (txNew), this , coin_control.fAllowWatchOnly );
3043
3004
nBytes = tx_sizes.first ;
3044
3005
if (nBytes < 0 ) {
3045
3006
error = _ (" Signing transaction failed" );
3046
3007
return false ;
3047
3008
}
3009
+ nFeeRet = coin_selection_params.m_effective_feerate .GetFee (nBytes);
3048
3010
3049
- nFeeNeeded = coin_selection_params.m_effective_feerate .GetFee (nBytes);
3050
- if (nFeeRet >= nFeeNeeded) {
3051
- // Reduce fee to only the needed amount if possible. This
3052
- // prevents potential overpayment in fees if the coins
3053
- // selected to meet nFeeNeeded result in a transaction that
3054
- // requires less fee than the prior iteration.
3055
-
3056
- // If we have no change and a big enough excess fee, then
3057
- // try to construct transaction again only without picking
3058
- // new inputs. We now know we only need the smaller fee
3059
- // (because of reduced tx size) and so we should add a
3060
- // change output. Only try this once.
3061
- if (nChangePosInOut == -1 && nSubtractFeeFromAmount == 0 && pick_new_inputs) {
3062
- unsigned int tx_size_with_change = nBytes + coin_selection_params.change_output_size + 2 ; // Add 2 as a buffer in case increasing # of outputs changes compact size
3063
- CAmount fee_needed_with_change = coin_selection_params.m_effective_feerate .GetFee (tx_size_with_change);
3064
- CAmount minimum_value_for_change = GetDustThreshold (change_prototype_txout, coin_selection_params.m_discard_feerate );
3065
- if (nFeeRet >= fee_needed_with_change + minimum_value_for_change) {
3066
- pick_new_inputs = false ;
3067
- nFeeRet = fee_needed_with_change;
3068
- continue ;
3069
- }
3070
- }
3071
-
3072
- // If we have change output already, just increase it
3073
- if (nFeeRet > nFeeNeeded && nChangePosInOut != -1 && nSubtractFeeFromAmount == 0 ) {
3074
- CAmount extraFeePaid = nFeeRet - nFeeNeeded;
3075
- std::vector<CTxOut>::iterator change_position = txNew.vout .begin ()+nChangePosInOut;
3076
- change_position->nValue += extraFeePaid;
3077
- nFeeRet -= extraFeePaid;
3078
- }
3079
- break ; // Done, enough fee included.
3080
- }
3081
- else if (!pick_new_inputs) {
3082
- // This shouldn't happen, we should have had enough excess
3083
- // fee to pay for the new output and still meet nFeeNeeded
3084
- // Or we should have just subtracted fee from recipients and
3085
- // nFeeNeeded should not have changed
3086
- error = _ (" Transaction fee and change calculation failed" );
3087
- return false ;
3011
+ // Subtract fee from the change output if not subtrating it from recipient outputs
3012
+ CAmount fee_needed = nFeeRet;
3013
+ if (nSubtractFeeFromAmount == 0 ) {
3014
+ change_position->nValue -= fee_needed;
3088
3015
}
3089
3016
3090
- // Try to reduce change to include necessary fee
3091
- if (nChangePosInOut != -1 && nSubtractFeeFromAmount == 0 ) {
3092
- CAmount additionalFeeNeeded = nFeeNeeded - nFeeRet;
3093
- std::vector<CTxOut>::iterator change_position = txNew.vout .begin ()+nChangePosInOut;
3094
- // Only reduce change if remaining amount is still a large enough output.
3095
- if (change_position->nValue >= MIN_FINAL_CHANGE + additionalFeeNeeded) {
3096
- change_position->nValue -= additionalFeeNeeded;
3097
- nFeeRet += additionalFeeNeeded;
3098
- break ; // Done, able to increase fee from change
3099
- }
3017
+ // We want to drop the change to fees if:
3018
+ // 1. The change output would be dust
3019
+ // 2. The change is within the (almost) exact match window, i.e. it is less than or equal to the cost of the change output (cost_of_change)
3020
+ CAmount change_amount = change_position->nValue ;
3021
+ if (IsDust (*change_position, coin_selection_params.m_discard_feerate ) || change_amount <= coin_selection_params.m_cost_of_change )
3022
+ {
3023
+ nChangePosInOut = -1 ;
3024
+ change_amount = 0 ;
3025
+ txNew.vout .erase (change_position);
3026
+
3027
+ // Because we have dropped this change, the tx size and required fee will be different, so let's recalculate those
3028
+ tx_sizes = CalculateMaximumSignedTxSize (CTransaction (txNew), this , coin_control.fAllowWatchOnly );
3029
+ nBytes = tx_sizes.first ;
3030
+ fee_needed = coin_selection_params.m_effective_feerate .GetFee (nBytes);
3100
3031
}
3101
3032
3102
- // If subtracting fee from recipients, we now know what fee we
3103
- // need to subtract, we have no reason to reselect inputs
3104
- if (nSubtractFeeFromAmount > 0 ) {
3105
- pick_new_inputs = false ;
3033
+ // If the fee is covered, there's no need to loop or subtract from recipients
3034
+ if (fee_needed <= change_and_fee - change_amount) {
3035
+ nFeeRet = change_and_fee - change_amount;
3036
+ break ;
3106
3037
}
3107
3038
3108
- // Include more fee and try again.
3109
- nFeeRet = nFeeNeeded;
3110
- coin_selection_params.use_bnb = false ;
3111
- continue ;
3039
+ // Reduce output values for subtractFeeFromAmount
3040
+ if (nSubtractFeeFromAmount != 0 ) {
3041
+ CAmount to_reduce = fee_needed + change_amount - change_and_fee;
3042
+ int i = 0 ;
3043
+ bool fFirst = true ;
3044
+ for (const auto & recipient : vecSend)
3045
+ {
3046
+ if (i == nChangePosInOut) {
3047
+ ++i;
3048
+ }
3049
+ CTxOut& txout = txNew.vout [i];
3050
+
3051
+ if (recipient.fSubtractFeeFromAmount )
3052
+ {
3053
+ txout.nValue -= to_reduce / nSubtractFeeFromAmount; // Subtract fee equally from each selected recipient
3054
+
3055
+ if (fFirst ) // first receiver pays the remainder not divisible by output count
3056
+ {
3057
+ fFirst = false ;
3058
+ txout.nValue -= to_reduce % nSubtractFeeFromAmount;
3059
+ }
3060
+
3061
+ // Error if this output is reduced to be below dust
3062
+ if (IsDust (txout, chain ().relayDustFee ())) {
3063
+ if (txout.nValue < 0 ) {
3064
+ error = _ (" The transaction amount is too small to pay the fee" );
3065
+ } else {
3066
+ error = _ (" The transaction amount is too small to send after the fee has been deducted" );
3067
+ }
3068
+ return false ;
3069
+ }
3070
+ }
3071
+ ++i;
3072
+ }
3073
+ nFeeRet = fee_needed;
3074
+ break ; // The fee has been deducted from the recipients, nothing left to do here
3075
+ }
3112
3076
}
3113
3077
3114
3078
// Give up if change keypool ran out and change is required
@@ -3170,8 +3134,8 @@ bool CWallet::CreateTransactionInternal(
3170
3134
reservedest.KeepDestination ();
3171
3135
fee_calc_out = feeCalc;
3172
3136
3173
- WalletLogPrintf (" Fee Calculation: Fee:%d Bytes:%u Needed:%d Tgt:%d (requested %d) Reason:\" %s\" Decay %.5f: Estimation: (%g - %g) %.2f%% %.1f/(%.1f %d mem %.1f out) Fail: (%g - %g) %.2f%% %.1f/(%.1f %d mem %.1f out)\n " ,
3174
- nFeeRet, nBytes, nFeeNeeded, feeCalc.returnedTarget , feeCalc.desiredTarget , StringForFeeReason (feeCalc.reason ), feeCalc.est .decay ,
3137
+ WalletLogPrintf (" Fee Calculation: Fee:%d Bytes:%u Tgt:%d (requested %d) Reason:\" %s\" Decay %.5f: Estimation: (%g - %g) %.2f%% %.1f/(%.1f %d mem %.1f out) Fail: (%g - %g) %.2f%% %.1f/(%.1f %d mem %.1f out)\n " ,
3138
+ nFeeRet, nBytes, feeCalc.returnedTarget , feeCalc.desiredTarget , StringForFeeReason (feeCalc.reason ), feeCalc.est .decay ,
3175
3139
feeCalc.est .pass .start , feeCalc.est .pass .end ,
3176
3140
(feeCalc.est .pass .totalConfirmed + feeCalc.est .pass .inMempool + feeCalc.est .pass .leftMempool ) > 0.0 ? 100 * feeCalc.est .pass .withinTarget / (feeCalc.est .pass .totalConfirmed + feeCalc.est .pass .inMempool + feeCalc.est .pass .leftMempool ) : 0.0 ,
3177
3141
feeCalc.est .pass .withinTarget , feeCalc.est .pass .totalConfirmed , feeCalc.est .pass .inMempool , feeCalc.est .pass .leftMempool ,
0 commit comments