Changeset View
Changeset View
Standalone View
Standalone View
src/wallet/wallet.cpp
Show First 20 Lines • Show All 2,745 Lines • ▼ Show 20 Lines | for (size_t idx = 0; idx < tx.vout.size(); idx++) { | ||||
vecSend.push_back(recipient); | vecSend.push_back(recipient); | ||||
} | } | ||||
CCoinControl coinControl; | CCoinControl coinControl; | ||||
coinControl.destChange = destChange; | coinControl.destChange = destChange; | ||||
coinControl.fAllowOtherInputs = true; | coinControl.fAllowOtherInputs = true; | ||||
coinControl.fAllowWatchOnly = includeWatching; | coinControl.fAllowWatchOnly = includeWatching; | ||||
coinControl.fOverrideFeeRate = overrideEstimatedFeeRate; | coinControl.fOverrideFeeRate = overrideEstimatedFeeRate; | ||||
coinControl.nFeeRate = specificFeeRate; | coinControl.m_feerate = specificFeeRate; | ||||
Fabien: Also this is not part of the original PR and shouldn't be needed after PR9672 | |||||
for (const CTxIn &txin : tx.vin) { | for (const CTxIn &txin : tx.vin) { | ||||
coinControl.Select(txin.prevout); | coinControl.Select(txin.prevout); | ||||
} | } | ||||
CReserveKey reservekey(this); | CReserveKey reservekey(this); | ||||
CWalletTx wtx; | CWalletTx wtx; | ||||
if (!CreateTransaction(vecSend, wtx, reservekey, nFeeRet, nChangePosInOut, | if (!CreateTransaction(vecSend, wtx, reservekey, nFeeRet, nChangePosInOut, | ||||
strFailReason, &coinControl, false)) { | strFailReason, coinControl, false)) { | ||||
return false; | return false; | ||||
} | } | ||||
if (nChangePosInOut != -1) { | if (nChangePosInOut != -1) { | ||||
tx.vout.insert(tx.vout.begin() + nChangePosInOut, | tx.vout.insert(tx.vout.begin() + nChangePosInOut, | ||||
wtx.tx->vout[nChangePosInOut]); | wtx.tx->vout[nChangePosInOut]); | ||||
} | } | ||||
Show All 22 Lines | bool CWallet::FundTransaction(CMutableTransaction &tx, Amount &nFeeRet, | ||||
return true; | return true; | ||||
} | } | ||||
bool CWallet::CreateTransaction(const std::vector<CRecipient> &vecSend, | bool CWallet::CreateTransaction(const std::vector<CRecipient> &vecSend, | ||||
CWalletTx &wtxNew, CReserveKey &reservekey, | CWalletTx &wtxNew, CReserveKey &reservekey, | ||||
Amount &nFeeRet, int &nChangePosInOut, | Amount &nFeeRet, int &nChangePosInOut, | ||||
std::string &strFailReason, | std::string &strFailReason, | ||||
const CCoinControl *coinControl, bool sign) { | const CCoinControl &coinControl, bool sign) { | ||||
Amount nValue = Amount::zero(); | Amount nValue = Amount::zero(); | ||||
int nChangePosRequest = nChangePosInOut; | int nChangePosRequest = nChangePosInOut; | ||||
unsigned int nSubtractFeeFromAmount = 0; | unsigned int nSubtractFeeFromAmount = 0; | ||||
for (const auto &recipient : vecSend) { | for (const auto &recipient : vecSend) { | ||||
if (nValue < Amount::zero() || recipient.nAmount < Amount::zero()) { | if (nValue < Amount::zero() || recipient.nAmount < Amount::zero()) { | ||||
strFailReason = _("Transaction amounts must not be negative"); | strFailReason = _("Transaction amounts must not be negative"); | ||||
return false; | return false; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 46 Lines • ▼ Show 20 Lines | bool CWallet::CreateTransaction(const std::vector<CRecipient> &vecSend, | ||||
assert(txNew.nLockTime <= (unsigned int)chainActive.Height()); | assert(txNew.nLockTime <= (unsigned int)chainActive.Height()); | ||||
assert(txNew.nLockTime < LOCKTIME_THRESHOLD); | assert(txNew.nLockTime < LOCKTIME_THRESHOLD); | ||||
{ | { | ||||
std::set<CInputCoin> setCoins; | std::set<CInputCoin> setCoins; | ||||
LOCK2(cs_main, cs_wallet); | LOCK2(cs_main, cs_wallet); | ||||
std::vector<COutput> vAvailableCoins; | std::vector<COutput> vAvailableCoins; | ||||
AvailableCoins(vAvailableCoins, true, coinControl); | AvailableCoins(vAvailableCoins, true, &coinControl); | ||||
// Create change script that will be used if we need change | // Create change script that will be used if we need change | ||||
// TODO: pass in scriptChange instead of reservekey so | // TODO: pass in scriptChange instead of reservekey so | ||||
// change transaction isn't always pay-to-bitcoin-address | // change transaction isn't always pay-to-bitcoin-address | ||||
CScript scriptChange; | CScript scriptChange; | ||||
// coin control: send change to custom address | // coin control: send change to custom address | ||||
if (coinControl && | if (!boost::get<CNoDestination>(&coinControl.destChange)) { | ||||
!boost::get<CNoDestination>(&coinControl->destChange)) { | scriptChange = GetScriptForDestination(coinControl.destChange); | ||||
scriptChange = GetScriptForDestination(coinControl->destChange); | |||||
// no coin control: send change to newly generated address | // no coin control: send change to newly generated address | ||||
} else { | } else { | ||||
// Note: We use a new key here to keep it from being obvious | // Note: We use a new key here to keep it from being obvious | ||||
// which side is the change. | // which side is the change. | ||||
// The drawback is that by not reusing a previous key, the | // The drawback is that by not reusing a previous key, the | ||||
// change may be lost if a backup is restored, if the backup | // change may be lost if a backup is restored, if the backup | ||||
// doesn't have the new private key for the change. If we | // doesn't have the new private key for the change. If we | ||||
▲ Show 20 Lines • Show All 71 Lines • ▼ Show 20 Lines | assert(txNew.nLockTime < LOCKTIME_THRESHOLD); | ||||
txNew.vout.push_back(txout); | txNew.vout.push_back(txout); | ||||
} | } | ||||
// Choose coins to use | // Choose coins to use | ||||
if (pick_new_inputs) { | if (pick_new_inputs) { | ||||
nValueIn = Amount::zero(); | nValueIn = Amount::zero(); | ||||
setCoins.clear(); | setCoins.clear(); | ||||
if (!SelectCoins(vAvailableCoins, nValueToSelect, setCoins, | if (!SelectCoins(vAvailableCoins, nValueToSelect, setCoins, | ||||
nValueIn, coinControl)) { | nValueIn, &coinControl)) { | ||||
strFailReason = _("Insufficient funds"); | strFailReason = _("Insufficient funds"); | ||||
return false; | return false; | ||||
} | } | ||||
} | } | ||||
for (const auto &pcoin : setCoins) { | for (const auto &pcoin : setCoins) { | ||||
Amount nCredit = pcoin.txout.nValue; | Amount nCredit = pcoin.txout.nValue; | ||||
// The coin age after the next block (depth+1) is used instead | // The coin age after the next block (depth+1) is used instead | ||||
▲ Show 20 Lines • Show All 87 Lines • ▼ Show 20 Lines | assert(txNew.nLockTime < LOCKTIME_THRESHOLD); | ||||
// Remove scriptSigs to eliminate the fee calculation dummy | // Remove scriptSigs to eliminate the fee calculation dummy | ||||
// signatures. | // signatures. | ||||
for (auto &vin : txNew.vin) { | for (auto &vin : txNew.vin) { | ||||
vin.scriptSig = CScript(); | vin.scriptSig = CScript(); | ||||
} | } | ||||
Amount nFeeNeeded = GetMinimumFee(nBytes, g_mempool); | Amount nFeeNeeded = GetMinimumFee(nBytes, g_mempool); | ||||
if (coinControl && coinControl->fOverrideFeeRate) { | |||||
nFeeNeeded = coinControl->nFeeRate.GetFeeCeiling(nBytes); | |||||
} | |||||
// If we made it here and we aren't even able to meet the relay fee | // If we made it here and we aren't even able to meet the relay fee | ||||
// on the next pass, give up because we must be at the maximum | // on the next pass, give up because we must be at the maximum | ||||
// allowed fee. | // allowed fee. | ||||
Amount minFee = GetConfig().GetMinFeePerKB().GetFeeCeiling(nBytes); | Amount minFee = GetConfig().GetMinFeePerKB().GetFeeCeiling(nBytes); | ||||
if (nFeeNeeded < minFee) { | if (nFeeNeeded < minFee) { | ||||
strFailReason = _("Transaction too large for fee policy"); | strFailReason = _("Transaction too large for fee policy"); | ||||
return false; | return false; | ||||
▲ Show 20 Lines • Show All 1,362 Lines • Show Last 20 Lines |
Also this is not part of the original PR and shouldn't be needed after PR9672