@@ -902,23 +902,20 @@ static util::Result<CreatedTransactionResult> CreateTransactionInternal(
902
902
}
903
903
TRACE5 (coin_selection, selected_coins, wallet.GetName ().c_str (), GetAlgorithmName (result->GetAlgo ()).c_str (), result->GetTarget (), result->GetWaste (), result->GetSelectedValue ());
904
904
905
- // Always make a change output
906
- // We will reduce the fee from this change output later, and remove the output if it is too small.
907
- const CAmount change_and_fee = result-> GetSelectedValue () - recipients_sum ;
908
- assert (change_and_fee >= 0 );
909
- CTxOut newTxOut (change_and_fee, scriptChange);
910
-
911
- if (nChangePosInOut == - 1 ) {
912
- // Insert change txn at random position:
913
- nChangePosInOut = rng_fast. randrange (txNew. vout . size () + 1 );
914
- }
915
- else if (( unsigned int )nChangePosInOut > txNew. vout . size ()) {
916
- return util::Error{ _ ( " Transaction change output index out of range " )} ;
905
+ const CAmount change_amount = result-> GetChange (coin_selection_params. min_viable_change , coin_selection_params. m_change_fee );
906
+ if (change_amount > 0 ) {
907
+ CTxOut newTxOut (change_amount, scriptChange) ;
908
+ if (nChangePosInOut == - 1 ) {
909
+ // Insert change txn at random position:
910
+ nChangePosInOut = rng_fast. randrange (txNew. vout . size () + 1 );
911
+ } else if (( unsigned int ) nChangePosInOut > txNew. vout . size () ) {
912
+ return util::Error{ _ ( " Transaction change output index out of range " )};
913
+ }
914
+ txNew. vout . insert (txNew. vout . begin () + nChangePosInOut, newTxOut);
915
+ } else {
916
+ nChangePosInOut = - 1 ;
917
917
}
918
918
919
- assert (nChangePosInOut != -1 );
920
- auto change_position = txNew.vout .insert (txNew.vout .begin () + nChangePosInOut, newTxOut);
921
-
922
919
// Shuffle selected coins and fill in final vin
923
920
std::vector<COutput> selected_coins = result->GetShuffledInputVector ();
924
921
@@ -942,42 +939,23 @@ static util::Result<CreatedTransactionResult> CreateTransactionInternal(
942
939
if (nBytes == -1 ) {
943
940
return util::Error{_ (" Missing solving data for estimating transaction size" )};
944
941
}
945
- nFeeRet = coin_selection_params.m_effective_feerate .GetFee (nBytes);
946
-
947
- // Subtract fee from the change output if not subtracting it from recipient outputs
948
- CAmount fee_needed = nFeeRet;
949
- if (!coin_selection_params.m_subtract_fee_outputs ) {
950
- change_position->nValue -= fee_needed;
951
- }
952
-
953
- // We want to drop the change to fees if:
954
- // 1. The change output would be dust
955
- // 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)
956
- CAmount change_amount = change_position->nValue ;
957
- if (IsDust (*change_position, coin_selection_params.m_discard_feerate ) || change_amount <= coin_selection_params.m_cost_of_change )
958
- {
959
- nChangePosInOut = -1 ;
960
- change_amount = 0 ;
961
- txNew.vout .erase (change_position);
942
+ CAmount fee_needed = coin_selection_params.m_effective_feerate .GetFee (nBytes);
943
+ nFeeRet = result->GetSelectedValue () - recipients_sum - change_amount;
962
944
963
- // Because we have dropped this change, the tx size and required fee will be different, so let's recalculate those
964
- tx_sizes = CalculateMaximumSignedTxSize (CTransaction (txNew), &wallet, &coin_control);
965
- nBytes = tx_sizes.vsize ;
966
- fee_needed = coin_selection_params.m_effective_feerate .GetFee (nBytes);
967
- }
968
-
969
- // The only time that fee_needed should be less than the amount available for fees (in change_and_fee - change_amount) is when
945
+ // The only time that fee_needed should be less than the amount available for fees is when
970
946
// we are subtracting the fee from the outputs. If this occurs at any other time, it is a bug.
971
- assert (coin_selection_params.m_subtract_fee_outputs || fee_needed <= change_and_fee - change_amount );
947
+ assert (coin_selection_params.m_subtract_fee_outputs || fee_needed <= nFeeRet );
972
948
973
- // Update nFeeRet in case fee_needed changed due to dropping the change output
974
- if (fee_needed <= change_and_fee - change_amount) {
975
- nFeeRet = change_and_fee - change_amount;
949
+ // If there is a change output and we overpay the fees then increase the change to match the fee needed
950
+ if (nChangePosInOut != -1 && fee_needed < nFeeRet) {
951
+ auto & change = txNew.vout .at (nChangePosInOut);
952
+ change.nValue += nFeeRet - fee_needed;
953
+ nFeeRet = fee_needed;
976
954
}
977
955
978
956
// Reduce output values for subtractFeeFromAmount
979
957
if (coin_selection_params.m_subtract_fee_outputs ) {
980
- CAmount to_reduce = fee_needed + change_amount - change_and_fee ;
958
+ CAmount to_reduce = fee_needed - nFeeRet ;
981
959
int i = 0 ;
982
960
bool fFirst = true ;
983
961
for (const auto & recipient : vecSend)
0 commit comments