Changeset View
Changeset View
Standalone View
Standalone View
src/wallet/wallet.cpp
Show First 20 Lines • Show All 2,986 Lines • ▼ Show 20 Lines | assert(txNew.nLockTime < LOCKTIME_THRESHOLD); | ||||
// First receiver pays the remainder not divisible by output | // First receiver pays the remainder not divisible by output | ||||
// count. | // count. | ||||
if (fFirst) { | if (fFirst) { | ||||
fFirst = false; | fFirst = false; | ||||
txout.nValue -= nFeeRet % int(nSubtractFeeFromAmount); | txout.nValue -= nFeeRet % int(nSubtractFeeFromAmount); | ||||
} | } | ||||
} | } | ||||
if (txout.IsDust(dustRelayFee)) { | if (IsDust(txout, dustRelayFee)) { | ||||
if (recipient.fSubtractFeeFromAmount && | if (recipient.fSubtractFeeFromAmount && | ||||
nFeeRet > Amount::zero()) { | nFeeRet > Amount::zero()) { | ||||
if (txout.nValue < Amount::zero()) { | if (txout.nValue < Amount::zero()) { | ||||
strFailReason = _("The transaction amount is " | strFailReason = _("The transaction amount is " | ||||
"too small to pay the fee"); | "too small to pay the fee"); | ||||
} else { | } else { | ||||
strFailReason = | strFailReason = | ||||
_("The transaction amount is too small to " | _("The transaction amount is too small to " | ||||
▲ Show 20 Lines • Show All 41 Lines • ▼ Show 20 Lines | assert(txNew.nLockTime < LOCKTIME_THRESHOLD); | ||||
// Fill a vout to ourself. | // Fill a vout to ourself. | ||||
CTxOut newTxOut(nChange, scriptChange); | CTxOut newTxOut(nChange, scriptChange); | ||||
// We do not move dust-change to fees, because the sender would | // We do not move dust-change to fees, because the sender would | ||||
// end up paying more than requested. This would be against the | // end up paying more than requested. This would be against the | ||||
// purpose of the all-inclusive feature. So instead we raise the | // purpose of the all-inclusive feature. So instead we raise the | ||||
// change and deduct from the recipient. | // change and deduct from the recipient. | ||||
if (nSubtractFeeFromAmount > 0 && | if (nSubtractFeeFromAmount > 0 && | ||||
newTxOut.IsDust(dustRelayFee)) { | IsDust(newTxOut, dustRelayFee)) { | ||||
Amount nDust = newTxOut.GetDustThreshold(dustRelayFee) - | Amount nDust = GetDustThreshold(newTxOut, dustRelayFee) - | ||||
newTxOut.nValue; | newTxOut.nValue; | ||||
// Raise change until no more dust. | // Raise change until no more dust. | ||||
newTxOut.nValue += nDust; | newTxOut.nValue += nDust; | ||||
// Subtract from first recipient. | // Subtract from first recipient. | ||||
for (unsigned int i = 0; i < vecSend.size(); i++) { | for (unsigned int i = 0; i < vecSend.size(); i++) { | ||||
if (vecSend[i].fSubtractFeeFromAmount) { | if (vecSend[i].fSubtractFeeFromAmount) { | ||||
txNew.vout[i].nValue -= nDust; | txNew.vout[i].nValue -= nDust; | ||||
if (txNew.vout[i].IsDust(dustRelayFee)) { | if (IsDust(txNew.vout[i], dustRelayFee)) { | ||||
strFailReason = | strFailReason = | ||||
_("The transaction amount is too small " | _("The transaction amount is too small " | ||||
"to send after the fee has been " | "to send after the fee has been " | ||||
"deducted"); | "deducted"); | ||||
return false; | return false; | ||||
} | } | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
} | } | ||||
// Never create dust outputs; if we would, just add the dust to | // Never create dust outputs; if we would, just add the dust to | ||||
// the fee. | // the fee. | ||||
if (newTxOut.IsDust(dustRelayFee)) { | if (IsDust(newTxOut, dustRelayFee)) { | ||||
nChangePosInOut = -1; | nChangePosInOut = -1; | ||||
nFeeRet += nChange; | nFeeRet += nChange; | ||||
} else { | } else { | ||||
if (nChangePosInOut == -1) { | if (nChangePosInOut == -1) { | ||||
// Insert change txn at random position: | // Insert change txn at random position: | ||||
nChangePosInOut = GetRandInt(txNew.vout.size() + 1); | nChangePosInOut = GetRandInt(txNew.vout.size() + 1); | ||||
} else if ((unsigned int)nChangePosInOut > | } else if ((unsigned int)nChangePosInOut > | ||||
txNew.vout.size()) { | txNew.vout.size()) { | ||||
▲ Show 20 Lines • Show All 59 Lines • ▼ Show 20 Lines | assert(txNew.nLockTime < LOCKTIME_THRESHOLD); | ||||
// If we have no change and a big enough excess fee, then try to | // If we have no change and a big enough excess fee, then try to | ||||
// construct transaction again only without picking new inputs. | // construct transaction again only without picking new inputs. | ||||
// We now know we only need the smaller fee (because of reduced | // We now know we only need the smaller fee (because of reduced | ||||
// tx size) and so we should add a change output. Only try this | // tx size) and so we should add a change output. Only try this | ||||
// once. | // once. | ||||
Amount fee_needed_for_change = GetMinimumFee( | Amount fee_needed_for_change = GetMinimumFee( | ||||
change_prototype_size, g_mempool, coinControl); | change_prototype_size, g_mempool, coinControl); | ||||
Amount minimum_value_for_change = | Amount minimum_value_for_change = | ||||
change_prototype_txout.GetDustThreshold(dustRelayFee); | GetDustThreshold(change_prototype_txout, dustRelayFee); | ||||
Amount max_excess_fee = | Amount max_excess_fee = | ||||
fee_needed_for_change + minimum_value_for_change; | fee_needed_for_change + minimum_value_for_change; | ||||
if (nFeeRet > nFeeNeeded + max_excess_fee && | if (nFeeRet > nFeeNeeded + max_excess_fee && | ||||
nChangePosInOut == -1 && nSubtractFeeFromAmount == 0 && | nChangePosInOut == -1 && nSubtractFeeFromAmount == 0 && | ||||
pick_new_inputs) { | pick_new_inputs) { | ||||
pick_new_inputs = false; | pick_new_inputs = false; | ||||
nFeeRet = nFeeNeeded + fee_needed_for_change; | nFeeRet = nFeeNeeded + fee_needed_for_change; | ||||
continue; | continue; | ||||
▲ Show 20 Lines • Show All 1,350 Lines • Show Last 20 Lines |