From 7c5de865d88d83c88e82f0b104a5eff6533a89b3 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Mon, 9 Jan 2017 08:20:41 -0800 Subject: [PATCH] Merge #9404: Smarter coordination of change and fee in CreateTransaction. 20449ef Don't overpay fee if we have selected new coins that result in a smaller transaction. (Alex Morcos) 42f5ce4 Try to reduce change output to make needed fee in CreateTransaction (Alex Morcos) --- src/wallet/wallet.cpp | 31 ++++++++++++++++++++++++++++++- src/wallet/wallet.h | 4 +++- 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index dea1a346f4..1f622ced82 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -3669,8 +3669,37 @@ bool CWallet::CreateTransaction(const vector& vecSend, CWalletTx& wt return false; } - if (nFeeRet >= nFeeNeeded) + if (nFeeRet >= nFeeNeeded) { + // Reduce fee to only the needed amount if we have change + // output to increase. This prevents potential overpayment + // in fees if the coins selected to meet nFeeNeeded result + // in a transaction that requires less fee than the prior + // iteration. + // TODO: The case where nSubtractFeeFromAmount > 0 remains + // to be addressed because it requires returning the fee to + // the payees and not the change output. + // TODO: The case where there is no change output remains + // to be addressed so we avoid creating too small an output. + if (nFeeRet > nFeeNeeded && nChangePosInOut != -1 && nSubtractFeeFromAmount == 0) { + CAmount extraFeePaid = nFeeRet - nFeeNeeded; + vector::iterator change_position = txNew.vout.begin()+nChangePosInOut; + change_position->nValue += extraFeePaid; + nFeeRet -= extraFeePaid; + } break; // Done, enough fee included. + } + + // Try to reduce change to include necessary fee + if (nChangePosInOut != -1 && nSubtractFeeFromAmount == 0) { + CAmount additionalFeeNeeded = nFeeNeeded - nFeeRet; + vector::iterator change_position = txNew.vout.begin()+nChangePosInOut; + // Only reduce change if remaining amount is still a large enough output. + if (change_position->nValue >= MIN_FINAL_CHANGE + additionalFeeNeeded) { + change_position->nValue -= additionalFeeNeeded; + nFeeRet += additionalFeeNeeded; + break; // Done, able to increase fee from change + } + } // Include more fee and try again. nFeeRet = nFeeNeeded; diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 399c6843af..2a8887e1c9 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -52,8 +52,10 @@ static const CAmount DEFAULT_TRANSACTION_FEE = 0; static const CAmount DEFAULT_FALLBACK_FEE = 1000; //! -mintxfee default static const CAmount DEFAULT_TRANSACTION_MINFEE = 1000; -//! minimum change amount +//! target minimum change amount static const CAmount MIN_CHANGE = CENT; +//! final minimum change amount after paying for fees +static const CAmount MIN_FINAL_CHANGE = MIN_CHANGE/2; //! Default for -spendzeroconfchange static const bool DEFAULT_SPEND_ZEROCONF_CHANGE = true; //! Default for -sendfreetransactions