@@ -902,23 +902,20 @@ static util::Result<CreatedTransactionResult> CreateTransactionInternal(
902902 }
903903 TRACE5 (coin_selection, selected_coins, wallet.GetName ().c_str (), GetAlgorithmName (result->GetAlgo ()).c_str (), result->GetTarget (), result->GetWaste (), result->GetSelectedValue ());
904904
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 ;
917917 }
918918
919- assert (nChangePosInOut != -1 );
920- auto change_position = txNew.vout .insert (txNew.vout .begin () + nChangePosInOut, newTxOut);
921-
922919 // Shuffle selected coins and fill in final vin
923920 std::vector<COutput> selected_coins = result->GetShuffledInputVector ();
924921
@@ -942,42 +939,23 @@ static util::Result<CreatedTransactionResult> CreateTransactionInternal(
942939 if (nBytes == -1 ) {
943940 return util::Error{_ (" Missing solving data for estimating transaction size" )};
944941 }
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;
962944
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
970946 // 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 );
972948
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;
976954 }
977955
978956 // Reduce output values for subtractFeeFromAmount
979957 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 ;
981959 int i = 0 ;
982960 bool fFirst = true ;
983961 for (const auto & recipient : vecSend)
0 commit comments