Changeset View
Changeset View
Standalone View
Standalone View
src/wallet/wallet.cpp
Show First 20 Lines • Show All 1,367 Lines • ▼ Show 20 Lines | if (mi != mapWallet.end()) { | ||||
const CWalletTx &prev = (*mi).second; | const CWalletTx &prev = (*mi).second; | ||||
if (txin.prevout.n < prev.tx->vout.size()) { | if (txin.prevout.n < prev.tx->vout.size()) { | ||||
if (IsMine(prev.tx->vout[txin.prevout.n]) & filter) { | if (IsMine(prev.tx->vout[txin.prevout.n]) & filter) { | ||||
return prev.tx->vout[txin.prevout.n].nValue; | return prev.tx->vout[txin.prevout.n].nValue; | ||||
} | } | ||||
} | } | ||||
} | } | ||||
return 0; | return Amount(0); | ||||
} | } | ||||
isminetype CWallet::IsMine(const CTxOut &txout) const { | isminetype CWallet::IsMine(const CTxOut &txout) const { | ||||
return ::IsMine(*this, txout.scriptPubKey); | return ::IsMine(*this, txout.scriptPubKey); | ||||
} | } | ||||
Amount CWallet::GetCredit(const CTxOut &txout, | Amount CWallet::GetCredit(const CTxOut &txout, | ||||
const isminefilter &filter) const { | const isminefilter &filter) const { | ||||
Show All 30 Lines | |||||
} | } | ||||
Amount CWallet::GetChange(const CTxOut &txout) const { | Amount CWallet::GetChange(const CTxOut &txout) const { | ||||
if (!MoneyRange(txout.nValue)) { | if (!MoneyRange(txout.nValue)) { | ||||
throw std::runtime_error(std::string(__func__) + | throw std::runtime_error(std::string(__func__) + | ||||
": value out of range"); | ": value out of range"); | ||||
} | } | ||||
return (IsChange(txout) ? txout.nValue : 0); | return (IsChange(txout) ? txout.nValue : Amount(0)); | ||||
} | } | ||||
bool CWallet::IsMine(const CTransaction &tx) const { | bool CWallet::IsMine(const CTransaction &tx) const { | ||||
for (const CTxOut &txout : tx.vout) { | for (const CTxOut &txout : tx.vout) { | ||||
if (IsMine(txout)) { | if (IsMine(txout)) { | ||||
return true; | return true; | ||||
} | } | ||||
} | } | ||||
return false; | return false; | ||||
} | } | ||||
bool CWallet::IsFromMe(const CTransaction &tx) const { | bool CWallet::IsFromMe(const CTransaction &tx) const { | ||||
return GetDebit(tx, ISMINE_ALL) > 0; | return GetDebit(tx, ISMINE_ALL) > Amount(0); | ||||
} | } | ||||
Amount CWallet::GetDebit(const CTransaction &tx, | Amount CWallet::GetDebit(const CTransaction &tx, | ||||
const isminefilter &filter) const { | const isminefilter &filter) const { | ||||
Amount nDebit = 0; | Amount nDebit(0); | ||||
for (const CTxIn &txin : tx.vin) { | for (const CTxIn &txin : tx.vin) { | ||||
nDebit += GetDebit(txin, filter); | nDebit += GetDebit(txin, filter); | ||||
if (!MoneyRange(nDebit)) { | if (!MoneyRange(nDebit)) { | ||||
throw std::runtime_error(std::string(__func__) + | throw std::runtime_error(std::string(__func__) + | ||||
": value out of range"); | ": value out of range"); | ||||
} | } | ||||
} | } | ||||
Show All 23 Lines | for (const CTxIn &txin : tx.vin) { | ||||
} | } | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
Amount CWallet::GetCredit(const CTransaction &tx, | Amount CWallet::GetCredit(const CTransaction &tx, | ||||
const isminefilter &filter) const { | const isminefilter &filter) const { | ||||
Amount nCredit = 0; | Amount nCredit(0); | ||||
for (const CTxOut &txout : tx.vout) { | for (const CTxOut &txout : tx.vout) { | ||||
nCredit += GetCredit(txout, filter); | nCredit += GetCredit(txout, filter); | ||||
if (!MoneyRange(nCredit)) { | if (!MoneyRange(nCredit)) { | ||||
throw std::runtime_error(std::string(__func__) + | throw std::runtime_error(std::string(__func__) + | ||||
": value out of range"); | ": value out of range"); | ||||
} | } | ||||
} | } | ||||
return nCredit; | return nCredit; | ||||
} | } | ||||
Amount CWallet::GetChange(const CTransaction &tx) const { | Amount CWallet::GetChange(const CTransaction &tx) const { | ||||
Amount nChange = 0; | Amount nChange(0); | ||||
for (const CTxOut &txout : tx.vout) { | for (const CTxOut &txout : tx.vout) { | ||||
nChange += GetChange(txout); | nChange += GetChange(txout); | ||||
if (!MoneyRange(nChange)) { | if (!MoneyRange(nChange)) { | ||||
throw std::runtime_error(std::string(__func__) + | throw std::runtime_error(std::string(__func__) + | ||||
": value out of range"); | ": value out of range"); | ||||
} | } | ||||
} | } | ||||
▲ Show 20 Lines • Show All 102 Lines • ▼ Show 20 Lines | int CWalletTx::GetRequestCount() const { | ||||
return nRequests; | return nRequests; | ||||
} | } | ||||
void CWalletTx::GetAmounts(std::list<COutputEntry> &listReceived, | void CWalletTx::GetAmounts(std::list<COutputEntry> &listReceived, | ||||
std::list<COutputEntry> &listSent, Amount &nFee, | std::list<COutputEntry> &listSent, Amount &nFee, | ||||
std::string &strSentAccount, | std::string &strSentAccount, | ||||
const isminefilter &filter) const { | const isminefilter &filter) const { | ||||
nFee = 0; | nFee = Amount(0); | ||||
listReceived.clear(); | listReceived.clear(); | ||||
listSent.clear(); | listSent.clear(); | ||||
strSentAccount = strFromAccount; | strSentAccount = strFromAccount; | ||||
// Compute fee: | // Compute fee: | ||||
Amount nDebit = GetDebit(filter); | Amount nDebit = GetDebit(filter); | ||||
// debit>0 means we signed/sent this transaction. | // debit>0 means we signed/sent this transaction. | ||||
if (nDebit > 0) { | if (nDebit > Amount(0)) { | ||||
Amount nValueOut = tx->GetValueOut(); | Amount nValueOut = tx->GetValueOut(); | ||||
nFee = (nDebit - nValueOut); | nFee = (nDebit - nValueOut); | ||||
} | } | ||||
// Sent/received. | // Sent/received. | ||||
for (unsigned int i = 0; i < tx->vout.size(); ++i) { | for (unsigned int i = 0; i < tx->vout.size(); ++i) { | ||||
const CTxOut &txout = tx->vout[i]; | const CTxOut &txout = tx->vout[i]; | ||||
isminetype fIsMine = pwallet->IsMine(txout); | isminetype fIsMine = pwallet->IsMine(txout); | ||||
Show All 34 Lines | for (unsigned int i = 0; i < tx->vout.size(); ++i) { | ||||
} | } | ||||
} | } | ||||
} | } | ||||
void CWalletTx::GetAccountAmounts(const std::string &strAccount, | void CWalletTx::GetAccountAmounts(const std::string &strAccount, | ||||
Amount &nReceived, Amount &nSent, | Amount &nReceived, Amount &nSent, | ||||
Amount &nFee, | Amount &nFee, | ||||
const isminefilter &filter) const { | const isminefilter &filter) const { | ||||
nReceived = nSent = nFee = 0; | nReceived = nSent = nFee = Amount(0); | ||||
Amount allFee; | Amount allFee; | ||||
std::string strSentAccount; | std::string strSentAccount; | ||||
std::list<COutputEntry> listReceived; | std::list<COutputEntry> listReceived; | ||||
std::list<COutputEntry> listSent; | std::list<COutputEntry> listSent; | ||||
GetAmounts(listReceived, listSent, allFee, strSentAccount, filter); | GetAmounts(listReceived, listSent, allFee, strSentAccount, filter); | ||||
if (strAccount == strSentAccount) { | if (strAccount == strSentAccount) { | ||||
▲ Show 20 Lines • Show All 154 Lines • ▼ Show 20 Lines | if (pwallet != nullptr) { | ||||
result = pwallet->GetConflicts(myHash); | result = pwallet->GetConflicts(myHash); | ||||
result.erase(myHash); | result.erase(myHash); | ||||
} | } | ||||
return result; | return result; | ||||
} | } | ||||
Amount CWalletTx::GetDebit(const isminefilter &filter) const { | Amount CWalletTx::GetDebit(const isminefilter &filter) const { | ||||
if (tx->vin.empty()) return 0; | if (tx->vin.empty()) return Amount(0); | ||||
Amount debit = 0; | Amount debit(0); | ||||
if (filter & ISMINE_SPENDABLE) { | if (filter & ISMINE_SPENDABLE) { | ||||
if (fDebitCached) { | if (fDebitCached) { | ||||
debit += nDebitCached; | debit += nDebitCached; | ||||
} else { | } else { | ||||
nDebitCached = pwallet->GetDebit(*this, ISMINE_SPENDABLE); | nDebitCached = pwallet->GetDebit(*this, ISMINE_SPENDABLE); | ||||
fDebitCached = true; | fDebitCached = true; | ||||
debit += nDebitCached; | debit += nDebitCached; | ||||
} | } | ||||
Show All 11 Lines | Amount CWalletTx::GetDebit(const isminefilter &filter) const { | ||||
return debit; | return debit; | ||||
} | } | ||||
Amount CWalletTx::GetCredit(const isminefilter &filter) const { | Amount CWalletTx::GetCredit(const isminefilter &filter) const { | ||||
// Must wait until coinbase is safely deep enough in the chain before | // Must wait until coinbase is safely deep enough in the chain before | ||||
// valuing it. | // valuing it. | ||||
if (IsCoinBase() && GetBlocksToMaturity() > 0) { | if (IsCoinBase() && GetBlocksToMaturity() > 0) { | ||||
return 0; | return Amount(0); | ||||
} | } | ||||
Amount credit = 0; | Amount credit(0); | ||||
if (filter & ISMINE_SPENDABLE) { | if (filter & ISMINE_SPENDABLE) { | ||||
// GetBalance can assume transactions in mapWallet won't change. | // GetBalance can assume transactions in mapWallet won't change. | ||||
if (fCreditCached) { | if (fCreditCached) { | ||||
credit += nCreditCached; | credit += nCreditCached; | ||||
} else { | } else { | ||||
nCreditCached = pwallet->GetCredit(*this, ISMINE_SPENDABLE); | nCreditCached = pwallet->GetCredit(*this, ISMINE_SPENDABLE); | ||||
fCreditCached = true; | fCreditCached = true; | ||||
credit += nCreditCached; | credit += nCreditCached; | ||||
Show All 16 Lines | |||||
Amount CWalletTx::GetImmatureCredit(bool fUseCache) const { | Amount CWalletTx::GetImmatureCredit(bool fUseCache) const { | ||||
if (IsCoinBase() && GetBlocksToMaturity() > 0 && IsInMainChain()) { | if (IsCoinBase() && GetBlocksToMaturity() > 0 && IsInMainChain()) { | ||||
if (fUseCache && fImmatureCreditCached) return nImmatureCreditCached; | if (fUseCache && fImmatureCreditCached) return nImmatureCreditCached; | ||||
nImmatureCreditCached = pwallet->GetCredit(*this, ISMINE_SPENDABLE); | nImmatureCreditCached = pwallet->GetCredit(*this, ISMINE_SPENDABLE); | ||||
fImmatureCreditCached = true; | fImmatureCreditCached = true; | ||||
return nImmatureCreditCached; | return nImmatureCreditCached; | ||||
} | } | ||||
return 0; | return Amount(0); | ||||
} | } | ||||
Amount CWalletTx::GetAvailableCredit(bool fUseCache) const { | Amount CWalletTx::GetAvailableCredit(bool fUseCache) const { | ||||
if (pwallet == 0) { | if (pwallet == 0) { | ||||
return 0; | return Amount(0); | ||||
} | } | ||||
// Must wait until coinbase is safely deep enough in the chain before | // Must wait until coinbase is safely deep enough in the chain before | ||||
// valuing it. | // valuing it. | ||||
if (IsCoinBase() && GetBlocksToMaturity() > 0) { | if (IsCoinBase() && GetBlocksToMaturity() > 0) { | ||||
return 0; | return Amount(0); | ||||
} | } | ||||
if (fUseCache && fAvailableCreditCached) { | if (fUseCache && fAvailableCreditCached) { | ||||
return nAvailableCreditCached; | return nAvailableCreditCached; | ||||
} | } | ||||
Amount nCredit = 0; | Amount nCredit(0); | ||||
uint256 hashTx = GetId(); | uint256 hashTx = GetId(); | ||||
for (unsigned int i = 0; i < tx->vout.size(); i++) { | for (unsigned int i = 0; i < tx->vout.size(); i++) { | ||||
if (!pwallet->IsSpent(hashTx, i)) { | if (!pwallet->IsSpent(hashTx, i)) { | ||||
const CTxOut &txout = tx->vout[i]; | const CTxOut &txout = tx->vout[i]; | ||||
nCredit += pwallet->GetCredit(txout, ISMINE_SPENDABLE); | nCredit += pwallet->GetCredit(txout, ISMINE_SPENDABLE); | ||||
if (!MoneyRange(nCredit)) { | if (!MoneyRange(nCredit)) { | ||||
throw std::runtime_error( | throw std::runtime_error( | ||||
"CWalletTx::GetAvailableCredit() : value out of range"); | "CWalletTx::GetAvailableCredit() : value out of range"); | ||||
Show All 13 Lines | if (IsCoinBase() && GetBlocksToMaturity() > 0 && IsInMainChain()) { | ||||
} | } | ||||
nImmatureWatchCreditCached = | nImmatureWatchCreditCached = | ||||
pwallet->GetCredit(*this, ISMINE_WATCH_ONLY); | pwallet->GetCredit(*this, ISMINE_WATCH_ONLY); | ||||
fImmatureWatchCreditCached = true; | fImmatureWatchCreditCached = true; | ||||
return nImmatureWatchCreditCached; | return nImmatureWatchCreditCached; | ||||
} | } | ||||
return 0; | return Amount(0); | ||||
} | } | ||||
Amount CWalletTx::GetAvailableWatchOnlyCredit(const bool &fUseCache) const { | Amount CWalletTx::GetAvailableWatchOnlyCredit(const bool &fUseCache) const { | ||||
if (pwallet == 0) { | if (pwallet == 0) { | ||||
return 0; | return Amount(0); | ||||
} | } | ||||
// Must wait until coinbase is safely deep enough in the chain before | // Must wait until coinbase is safely deep enough in the chain before | ||||
// valuing it. | // valuing it. | ||||
if (IsCoinBase() && GetBlocksToMaturity() > 0) { | if (IsCoinBase() && GetBlocksToMaturity() > 0) { | ||||
return 0; | return Amount(0); | ||||
} | } | ||||
if (fUseCache && fAvailableWatchCreditCached) { | if (fUseCache && fAvailableWatchCreditCached) { | ||||
return nAvailableWatchCreditCached; | return nAvailableWatchCreditCached; | ||||
} | } | ||||
Amount nCredit = 0; | Amount nCredit(0); | ||||
for (unsigned int i = 0; i < tx->vout.size(); i++) { | for (unsigned int i = 0; i < tx->vout.size(); i++) { | ||||
if (!pwallet->IsSpent(GetId(), i)) { | if (!pwallet->IsSpent(GetId(), i)) { | ||||
const CTxOut &txout = tx->vout[i]; | const CTxOut &txout = tx->vout[i]; | ||||
nCredit += pwallet->GetCredit(txout, ISMINE_WATCH_ONLY); | nCredit += pwallet->GetCredit(txout, ISMINE_WATCH_ONLY); | ||||
if (!MoneyRange(nCredit)) { | if (!MoneyRange(nCredit)) { | ||||
throw std::runtime_error( | throw std::runtime_error( | ||||
"CWalletTx::GetAvailableCredit() : value out of range"); | "CWalletTx::GetAvailableCredit() : value out of range"); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 144 Lines • ▼ Show 20 Lines | |||||
/** | /** | ||||
* @defgroup Actions | * @defgroup Actions | ||||
* | * | ||||
* @{ | * @{ | ||||
*/ | */ | ||||
Amount CWallet::GetBalance() const { | Amount CWallet::GetBalance() const { | ||||
LOCK2(cs_main, cs_wallet); | LOCK2(cs_main, cs_wallet); | ||||
Amount nTotal = 0; | Amount nTotal(0); | ||||
for (std::map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); | for (std::map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); | ||||
it != mapWallet.end(); ++it) { | it != mapWallet.end(); ++it) { | ||||
const CWalletTx *pcoin = &(*it).second; | const CWalletTx *pcoin = &(*it).second; | ||||
if (pcoin->IsTrusted()) { | if (pcoin->IsTrusted()) { | ||||
nTotal += pcoin->GetAvailableCredit(); | nTotal += pcoin->GetAvailableCredit(); | ||||
} | } | ||||
} | } | ||||
return nTotal; | return nTotal; | ||||
} | } | ||||
Amount CWallet::GetUnconfirmedBalance() const { | Amount CWallet::GetUnconfirmedBalance() const { | ||||
LOCK2(cs_main, cs_wallet); | LOCK2(cs_main, cs_wallet); | ||||
Amount nTotal = 0; | Amount nTotal(0); | ||||
for (std::map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); | for (std::map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); | ||||
it != mapWallet.end(); ++it) { | it != mapWallet.end(); ++it) { | ||||
const CWalletTx *pcoin = &(*it).second; | const CWalletTx *pcoin = &(*it).second; | ||||
if (!pcoin->IsTrusted() && pcoin->GetDepthInMainChain() == 0 && | if (!pcoin->IsTrusted() && pcoin->GetDepthInMainChain() == 0 && | ||||
pcoin->InMempool()) { | pcoin->InMempool()) { | ||||
nTotal += pcoin->GetAvailableCredit(); | nTotal += pcoin->GetAvailableCredit(); | ||||
} | } | ||||
} | } | ||||
return nTotal; | return nTotal; | ||||
} | } | ||||
Amount CWallet::GetImmatureBalance() const { | Amount CWallet::GetImmatureBalance() const { | ||||
LOCK2(cs_main, cs_wallet); | LOCK2(cs_main, cs_wallet); | ||||
Amount nTotal = 0; | Amount nTotal(0); | ||||
for (std::map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); | for (std::map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); | ||||
it != mapWallet.end(); ++it) { | it != mapWallet.end(); ++it) { | ||||
const CWalletTx *pcoin = &(*it).second; | const CWalletTx *pcoin = &(*it).second; | ||||
nTotal += pcoin->GetImmatureCredit(); | nTotal += pcoin->GetImmatureCredit(); | ||||
} | } | ||||
return nTotal; | return nTotal; | ||||
} | } | ||||
Amount CWallet::GetWatchOnlyBalance() const { | Amount CWallet::GetWatchOnlyBalance() const { | ||||
LOCK2(cs_main, cs_wallet); | LOCK2(cs_main, cs_wallet); | ||||
Amount nTotal = 0; | Amount nTotal(0); | ||||
for (std::map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); | for (std::map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); | ||||
it != mapWallet.end(); ++it) { | it != mapWallet.end(); ++it) { | ||||
const CWalletTx *pcoin = &(*it).second; | const CWalletTx *pcoin = &(*it).second; | ||||
if (pcoin->IsTrusted()) { | if (pcoin->IsTrusted()) { | ||||
nTotal += pcoin->GetAvailableWatchOnlyCredit(); | nTotal += pcoin->GetAvailableWatchOnlyCredit(); | ||||
} | } | ||||
} | } | ||||
return nTotal; | return nTotal; | ||||
} | } | ||||
Amount CWallet::GetUnconfirmedWatchOnlyBalance() const { | Amount CWallet::GetUnconfirmedWatchOnlyBalance() const { | ||||
LOCK2(cs_main, cs_wallet); | LOCK2(cs_main, cs_wallet); | ||||
Amount nTotal = 0; | Amount nTotal(0); | ||||
for (std::map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); | for (std::map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); | ||||
it != mapWallet.end(); ++it) { | it != mapWallet.end(); ++it) { | ||||
const CWalletTx *pcoin = &(*it).second; | const CWalletTx *pcoin = &(*it).second; | ||||
if (!pcoin->IsTrusted() && pcoin->GetDepthInMainChain() == 0 && | if (!pcoin->IsTrusted() && pcoin->GetDepthInMainChain() == 0 && | ||||
pcoin->InMempool()) { | pcoin->InMempool()) { | ||||
nTotal += pcoin->GetAvailableWatchOnlyCredit(); | nTotal += pcoin->GetAvailableWatchOnlyCredit(); | ||||
} | } | ||||
} | } | ||||
return nTotal; | return nTotal; | ||||
} | } | ||||
Amount CWallet::GetImmatureWatchOnlyBalance() const { | Amount CWallet::GetImmatureWatchOnlyBalance() const { | ||||
LOCK2(cs_main, cs_wallet); | LOCK2(cs_main, cs_wallet); | ||||
Amount nTotal = 0; | Amount nTotal(0); | ||||
for (std::map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); | for (std::map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); | ||||
it != mapWallet.end(); ++it) { | it != mapWallet.end(); ++it) { | ||||
const CWalletTx *pcoin = &(*it).second; | const CWalletTx *pcoin = &(*it).second; | ||||
nTotal += pcoin->GetImmatureWatchOnlyCredit(); | nTotal += pcoin->GetImmatureWatchOnlyCredit(); | ||||
} | } | ||||
return nTotal; | return nTotal; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 53 Lines • ▼ Show 20 Lines | for (std::map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); | ||||
pcoin->mapValue.count("replaced_by_txid")) { | pcoin->mapValue.count("replaced_by_txid")) { | ||||
continue; | continue; | ||||
} | } | ||||
for (unsigned int i = 0; i < pcoin->tx->vout.size(); i++) { | for (unsigned int i = 0; i < pcoin->tx->vout.size(); i++) { | ||||
isminetype mine = IsMine(pcoin->tx->vout[i]); | isminetype mine = IsMine(pcoin->tx->vout[i]); | ||||
if (!(IsSpent(wtxid, i)) && mine != ISMINE_NO && | if (!(IsSpent(wtxid, i)) && mine != ISMINE_NO && | ||||
!IsLockedCoin((*it).first, i) && | !IsLockedCoin((*it).first, i) && | ||||
(pcoin->tx->vout[i].nValue > 0 || fIncludeZeroValue) && | (pcoin->tx->vout[i].nValue > Amount(0) || fIncludeZeroValue) && | ||||
(!coinControl || !coinControl->HasSelected() || | (!coinControl || !coinControl->HasSelected() || | ||||
coinControl->fAllowOtherInputs || | coinControl->fAllowOtherInputs || | ||||
coinControl->IsSelected(COutPoint((*it).first, i)))) { | coinControl->IsSelected(COutPoint((*it).first, i)))) { | ||||
vCoins.push_back(COutput( | vCoins.push_back(COutput( | ||||
pcoin, i, nDepth, | pcoin, i, nDepth, | ||||
((mine & ISMINE_SPENDABLE) != ISMINE_NO) || | ((mine & ISMINE_SPENDABLE) != ISMINE_NO) || | ||||
(coinControl && coinControl->fAllowWatchOnly && | (coinControl && coinControl->fAllowWatchOnly && | ||||
(mine & ISMINE_WATCH_SOLVABLE) != ISMINE_NO), | (mine & ISMINE_WATCH_SOLVABLE) != ISMINE_NO), | ||||
Show All 13 Lines | static void ApproximateBestSubset( | ||||
vfBest.assign(vValue.size(), true); | vfBest.assign(vValue.size(), true); | ||||
nBest = nTotalLower; | nBest = nTotalLower; | ||||
FastRandomContext insecure_rand; | FastRandomContext insecure_rand; | ||||
for (int nRep = 0; nRep < iterations && nBest != nTargetValue; nRep++) { | for (int nRep = 0; nRep < iterations && nBest != nTargetValue; nRep++) { | ||||
vfIncluded.assign(vValue.size(), false); | vfIncluded.assign(vValue.size(), false); | ||||
Amount nTotal = 0; | Amount nTotal(0); | ||||
bool fReachedTarget = false; | bool fReachedTarget = false; | ||||
for (int nPass = 0; nPass < 2 && !fReachedTarget; nPass++) { | for (int nPass = 0; nPass < 2 && !fReachedTarget; nPass++) { | ||||
for (size_t i = 0; i < vValue.size(); i++) { | for (size_t i = 0; i < vValue.size(); i++) { | ||||
// The solver here uses a randomized algorithm, the randomness | // The solver here uses a randomized algorithm, the randomness | ||||
// serves no real security purpose but is just needed to prevent | // serves no real security purpose but is just needed to prevent | ||||
// degenerate behavior and it is important that the rng is fast. | // degenerate behavior and it is important that the rng is fast. | ||||
// We do not use a constant random sequence, because there may | // We do not use a constant random sequence, because there may | ||||
// be some privacy improvement by making the selection random. | // be some privacy improvement by making the selection random. | ||||
Show All 17 Lines | |||||
} | } | ||||
bool CWallet::SelectCoinsMinConf( | bool CWallet::SelectCoinsMinConf( | ||||
const Amount nTargetValue, const int nConfMine, const int nConfTheirs, | const Amount nTargetValue, const int nConfMine, const int nConfTheirs, | ||||
const uint64_t nMaxAncestors, std::vector<COutput> vCoins, | const uint64_t nMaxAncestors, std::vector<COutput> vCoins, | ||||
std::set<std::pair<const CWalletTx *, unsigned int>> &setCoinsRet, | std::set<std::pair<const CWalletTx *, unsigned int>> &setCoinsRet, | ||||
Amount &nValueRet) const { | Amount &nValueRet) const { | ||||
setCoinsRet.clear(); | setCoinsRet.clear(); | ||||
nValueRet = 0; | nValueRet = Amount(0); | ||||
// List of values less than target | // List of values less than target | ||||
std::pair<Amount, std::pair<const CWalletTx *, unsigned int>> | std::pair<Amount, std::pair<const CWalletTx *, unsigned int>> | ||||
coinLowestLarger; | coinLowestLarger; | ||||
coinLowestLarger.first = MAX_MONEY; | coinLowestLarger.first = MAX_MONEY; | ||||
coinLowestLarger.second.first = nullptr; | coinLowestLarger.second.first = nullptr; | ||||
std::vector<std::pair<Amount, std::pair<const CWalletTx *, unsigned int>>> | std::vector<std::pair<Amount, std::pair<const CWalletTx *, unsigned int>>> | ||||
vValue; | vValue; | ||||
Amount nTotalLower = 0; | Amount nTotalLower(0); | ||||
random_shuffle(vCoins.begin(), vCoins.end(), GetRandInt); | random_shuffle(vCoins.begin(), vCoins.end(), GetRandInt); | ||||
for (const COutput &output : vCoins) { | for (const COutput &output : vCoins) { | ||||
if (!output.fSpendable) { | if (!output.fSpendable) { | ||||
continue; | continue; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 106 Lines • ▼ Show 20 Lines | if (coinControl && coinControl->HasSelected() && | ||||
setCoinsRet.insert(std::make_pair(out.tx, out.i)); | setCoinsRet.insert(std::make_pair(out.tx, out.i)); | ||||
} | } | ||||
return (nValueRet >= nTargetValue); | return (nValueRet >= nTargetValue); | ||||
} | } | ||||
// Calculate value from preset inputs and store them. | // Calculate value from preset inputs and store them. | ||||
std::set<std::pair<const CWalletTx *, uint32_t>> setPresetCoins; | std::set<std::pair<const CWalletTx *, uint32_t>> setPresetCoins; | ||||
Amount nValueFromPresetInputs = 0; | Amount nValueFromPresetInputs(0); | ||||
std::vector<COutPoint> vPresetInputs; | std::vector<COutPoint> vPresetInputs; | ||||
if (coinControl) { | if (coinControl) { | ||||
coinControl->ListSelected(vPresetInputs); | coinControl->ListSelected(vPresetInputs); | ||||
} | } | ||||
for (const COutPoint &outpoint : vPresetInputs) { | for (const COutPoint &outpoint : vPresetInputs) { | ||||
std::map<uint256, CWalletTx>::const_iterator it = | std::map<uint256, CWalletTx>::const_iterator it = | ||||
▲ Show 20 Lines • Show All 131 Lines • ▼ Show 20 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 = 0; | Amount nValue(0); | ||||
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(0) || recipient.nAmount < Amount(0)) { | if (nValue < Amount(0) || recipient.nAmount < Amount(0)) { | ||||
strFailReason = _("Transaction amounts must not be negative"); | strFailReason = _("Transaction amounts must not be negative"); | ||||
return false; | return false; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 48 Lines • ▼ Show 20 Lines | bool CWallet::CreateTransaction(const std::vector<CRecipient> &vecSend, | ||||
{ | { | ||||
std::set<std::pair<const CWalletTx *, unsigned int>> setCoins; | std::set<std::pair<const CWalletTx *, unsigned int>> 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); | ||||
nFeeRet = 0; | nFeeRet = Amount(0); | ||||
// Start with no fee and loop until there is enough fee. | // Start with no fee and loop until there is enough fee. | ||||
while (true) { | while (true) { | ||||
nChangePosInOut = nChangePosRequest; | nChangePosInOut = nChangePosRequest; | ||||
txNew.vin.clear(); | txNew.vin.clear(); | ||||
txNew.vout.clear(); | txNew.vout.clear(); | ||||
wtxNew.fFromMe = true; | wtxNew.fFromMe = true; | ||||
bool fFirst = true; | bool fFirst = true; | ||||
Amount nValueToSelect = nValue; | Amount nValueToSelect = nValue; | ||||
if (nSubtractFeeFromAmount == 0) { | if (nSubtractFeeFromAmount == 0) { | ||||
nValueToSelect += nFeeRet; | nValueToSelect += nFeeRet; | ||||
} | } | ||||
double dPriority = 0; | double dPriority = 0; | ||||
// vouts to the payees | // vouts to the payees | ||||
for (const auto &recipient : vecSend) { | for (const auto &recipient : vecSend) { | ||||
CTxOut txout(recipient.nAmount, recipient.scriptPubKey); | CTxOut txout(recipient.nAmount, recipient.scriptPubKey); | ||||
if (recipient.fSubtractFeeFromAmount) { | if (recipient.fSubtractFeeFromAmount) { | ||||
// Subtract fee equally from each selected recipient. | // Subtract fee equally from each selected recipient. | ||||
txout.nValue -= | txout.nValue -= nFeeRet / int(nSubtractFeeFromAmount); | ||||
Amount(nFeeRet.GetSatoshis() / nSubtractFeeFromAmount); | |||||
// 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 -= | txout.nValue -= nFeeRet % int(nSubtractFeeFromAmount); | ||||
nFeeRet.GetSatoshis() % nSubtractFeeFromAmount; | |||||
} | } | ||||
} | } | ||||
if (txout.IsDust(dustRelayFee)) { | if (txout.IsDust(dustRelayFee)) { | ||||
if (recipient.fSubtractFeeFromAmount && nFeeRet > 0) { | if (recipient.fSubtractFeeFromAmount && | ||||
if (txout.nValue < 0) { | nFeeRet > Amount(0)) { | ||||
if (txout.nValue < Amount(0)) { | |||||
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 " | ||||
"send after the fee has been deducted"); | "send after the fee has been deducted"); | ||||
} | } | ||||
} else { | } else { | ||||
strFailReason = _("Transaction amount too small"); | strFailReason = _("Transaction amount too small"); | ||||
} | } | ||||
return false; | return false; | ||||
} | } | ||||
txNew.vout.push_back(txout); | txNew.vout.push_back(txout); | ||||
} | } | ||||
// Choose coins to use. | // Choose coins to use. | ||||
Amount nValueIn = 0; | Amount nValueIn(0); | ||||
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.first->tx->vout[pcoin.second].nValue; | Amount nCredit = pcoin.first->tx->vout[pcoin.second].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 | ||||
// of the current, reflecting an assumption the user would | // of the current, reflecting an assumption the user would | ||||
// accept a bit more delay for a chance at a free transaction. | // accept a bit more delay for a chance at a free transaction. | ||||
// But mempool inputs might still be in the mempool, so their | // But mempool inputs might still be in the mempool, so their | ||||
// age stays 0. | // age stays 0. | ||||
int age = pcoin.first->GetDepthInMainChain(); | int age = pcoin.first->GetDepthInMainChain(); | ||||
assert(age >= 0); | assert(age >= 0); | ||||
if (age != 0) age += 1; | if (age != 0) age += 1; | ||||
dPriority += (double)nCredit.GetSatoshis() * age; | dPriority += (double)nCredit.GetSatoshis() * age; | ||||
} | } | ||||
const Amount nChange = nValueIn - nValueToSelect; | const Amount nChange = nValueIn - nValueToSelect; | ||||
if (nChange > 0) { | if (nChange > Amount(0)) { | ||||
// Fill a vout to ourself. | // Fill a vout to ourself. | ||||
// TODO: pass in scriptChange instead of reservekey so change | // TODO: pass in scriptChange instead of reservekey so change | ||||
// transaction isn't always pay-to-bitcoin-address. | // 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 (coinControl && | ||||
!boost::get<CNoDestination>(&coinControl->destChange)) { | !boost::get<CNoDestination>(&coinControl->destChange)) { | ||||
▲ Show 20 Lines • Show All 120 Lines • ▼ Show 20 Lines | assert(txNew.nLockTime < LOCKTIME_THRESHOLD); | ||||
// Require at least hard-coded AllowFree. | // Require at least hard-coded AllowFree. | ||||
if (dPriority >= dPriorityNeeded && AllowFree(dPriority)) { | if (dPriority >= dPriorityNeeded && AllowFree(dPriority)) { | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
Amount nFeeNeeded = | Amount nFeeNeeded = | ||||
GetMinimumFee(nBytes, currentConfirmationTarget, mempool); | GetMinimumFee(nBytes, currentConfirmationTarget, mempool); | ||||
if (coinControl && nFeeNeeded > 0 && | if (coinControl && nFeeNeeded > Amount(0) && | ||||
coinControl->nMinimumTotalFee > nFeeNeeded) { | coinControl->nMinimumTotalFee > nFeeNeeded) { | ||||
nFeeNeeded = coinControl->nMinimumTotalFee; | nFeeNeeded = coinControl->nMinimumTotalFee; | ||||
} | } | ||||
if (coinControl && coinControl->fOverrideFeeRate) { | if (coinControl && coinControl->fOverrideFeeRate) { | ||||
nFeeNeeded = coinControl->nFeeRate.GetFee(nBytes); | nFeeNeeded = coinControl->nFeeRate.GetFee(nBytes); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 84 Lines • ▼ Show 20 Lines | assert(txNew.nLockTime < LOCKTIME_THRESHOLD); | ||||
return false; | return false; | ||||
} | } | ||||
} | } | ||||
if (GetBoolArg("-walletrejectlongchains", | if (GetBoolArg("-walletrejectlongchains", | ||||
DEFAULT_WALLET_REJECT_LONG_CHAINS)) { | DEFAULT_WALLET_REJECT_LONG_CHAINS)) { | ||||
// Lastly, ensure this tx will pass the mempool's chain limits. | // Lastly, ensure this tx will pass the mempool's chain limits. | ||||
LockPoints lp; | LockPoints lp; | ||||
CTxMemPoolEntry entry(wtxNew.tx, 0, 0, 0, 0, 0, false, 0, lp); | CTxMemPoolEntry entry(wtxNew.tx, Amount(0), 0, 0, 0, Amount(0), false, | ||||
0, lp); | |||||
CTxMemPool::setEntries setAncestors; | CTxMemPool::setEntries setAncestors; | ||||
size_t nLimitAncestors = | size_t nLimitAncestors = | ||||
GetArg("-limitancestorcount", DEFAULT_ANCESTOR_LIMIT); | GetArg("-limitancestorcount", DEFAULT_ANCESTOR_LIMIT); | ||||
size_t nLimitAncestorSize = | size_t nLimitAncestorSize = | ||||
GetArg("-limitancestorsize", DEFAULT_ANCESTOR_SIZE_LIMIT) * 1000; | GetArg("-limitancestorsize", DEFAULT_ANCESTOR_SIZE_LIMIT) * 1000; | ||||
size_t nLimitDescendants = | size_t nLimitDescendants = | ||||
GetArg("-limitdescendantcount", DEFAULT_DESCENDANT_LIMIT); | GetArg("-limitdescendantcount", DEFAULT_DESCENDANT_LIMIT); | ||||
size_t nLimitDescendantSize = | size_t nLimitDescendantSize = | ||||
▲ Show 20 Lines • Show All 90 Lines • ▼ Show 20 Lines | return GetMinimumFee(nTxBytes, nConfirmTarget, pool, | ||||
payTxFee.GetFee(nTxBytes)); | payTxFee.GetFee(nTxBytes)); | ||||
} | } | ||||
Amount CWallet::GetMinimumFee(unsigned int nTxBytes, | Amount CWallet::GetMinimumFee(unsigned int nTxBytes, | ||||
unsigned int nConfirmTarget, | unsigned int nConfirmTarget, | ||||
const CTxMemPool &pool, Amount targetFee) { | const CTxMemPool &pool, Amount targetFee) { | ||||
Amount nFeeNeeded = targetFee; | Amount nFeeNeeded = targetFee; | ||||
// User didn't set: use -txconfirmtarget to estimate... | // User didn't set: use -txconfirmtarget to estimate... | ||||
if (nFeeNeeded == 0) { | if (nFeeNeeded == Amount(0)) { | ||||
int estimateFoundTarget = nConfirmTarget; | int estimateFoundTarget = nConfirmTarget; | ||||
nFeeNeeded = pool.estimateSmartFee(nConfirmTarget, &estimateFoundTarget) | nFeeNeeded = pool.estimateSmartFee(nConfirmTarget, &estimateFoundTarget) | ||||
.GetFee(nTxBytes); | .GetFee(nTxBytes); | ||||
// ... unless we don't have enough mempool data for estimatefee, then | // ... unless we don't have enough mempool data for estimatefee, then | ||||
// use fallbackFee. | // use fallbackFee. | ||||
if (nFeeNeeded == 0) { | if (nFeeNeeded == Amount(0)) { | ||||
nFeeNeeded = fallbackFee.GetFee(nTxBytes); | nFeeNeeded = fallbackFee.GetFee(nTxBytes); | ||||
} | } | ||||
} | } | ||||
// Prevent user from paying a fee below minRelayTxFee or minTxFee. | // Prevent user from paying a fee below minRelayTxFee or minTxFee. | ||||
nFeeNeeded = std::max(nFeeNeeded, GetRequiredFee(nTxBytes)); | nFeeNeeded = std::max(nFeeNeeded, GetRequiredFee(nTxBytes)); | ||||
// But always obey the maximum. | // But always obey the maximum. | ||||
▲ Show 20 Lines • Show All 337 Lines • ▼ Show 20 Lines | for (std::pair<uint256, CWalletTx> walletEntry : mapWallet) { | ||||
if (!IsMine(pcoin->tx->vout[i])) { | if (!IsMine(pcoin->tx->vout[i])) { | ||||
continue; | continue; | ||||
} | } | ||||
if (!ExtractDestination(pcoin->tx->vout[i].scriptPubKey, addr)) { | if (!ExtractDestination(pcoin->tx->vout[i].scriptPubKey, addr)) { | ||||
continue; | continue; | ||||
} | } | ||||
Amount n = | Amount n = IsSpent(walletEntry.first, i) | ||||
IsSpent(walletEntry.first, i) ? 0 : pcoin->tx->vout[i].nValue; | ? Amount(0) | ||||
: pcoin->tx->vout[i].nValue; | |||||
if (!balances.count(addr)) balances[addr] = 0; | if (!balances.count(addr)) balances[addr] = Amount(0); | ||||
balances[addr] += n; | balances[addr] += n; | ||||
} | } | ||||
} | } | ||||
return balances; | return balances; | ||||
} | } | ||||
std::set<std::set<CTxDestination>> CWallet::GetAddressGroupings() { | std::set<std::set<CTxDestination>> CWallet::GetAddressGroupings() { | ||||
▲ Show 20 Lines • Show All 104 Lines • ▼ Show 20 Lines | Amount CWallet::GetAccountBalance(const std::string &strAccount, int nMinDepth, | ||||
const isminefilter &filter) { | const isminefilter &filter) { | ||||
CWalletDB walletdb(strWalletFile); | CWalletDB walletdb(strWalletFile); | ||||
return GetAccountBalance(walletdb, strAccount, nMinDepth, filter); | return GetAccountBalance(walletdb, strAccount, nMinDepth, filter); | ||||
} | } | ||||
Amount CWallet::GetAccountBalance(CWalletDB &walletdb, | Amount CWallet::GetAccountBalance(CWalletDB &walletdb, | ||||
const std::string &strAccount, int nMinDepth, | const std::string &strAccount, int nMinDepth, | ||||
const isminefilter &filter) { | const isminefilter &filter) { | ||||
Amount nBalance = 0; | Amount nBalance(0); | ||||
// Tally wallet transactions. | // Tally wallet transactions. | ||||
for (std::map<uint256, CWalletTx>::iterator it = mapWallet.begin(); | for (std::map<uint256, CWalletTx>::iterator it = mapWallet.begin(); | ||||
it != mapWallet.end(); ++it) { | it != mapWallet.end(); ++it) { | ||||
const CWalletTx &wtx = (*it).second; | const CWalletTx &wtx = (*it).second; | ||||
if (!CheckFinalTx(wtx) || wtx.GetBlocksToMaturity() > 0 || | if (!CheckFinalTx(wtx) || wtx.GetBlocksToMaturity() > 0 || | ||||
wtx.GetDepthInMainChain() < 0) { | wtx.GetDepthInMainChain() < 0) { | ||||
continue; | continue; | ||||
▲ Show 20 Lines • Show All 676 Lines • ▼ Show 20 Lines | bool CWallet::ParameterInteraction() { | ||||
if (::minRelayTxFee.GetFeePerK() > HIGH_TX_FEE_PER_KB) { | if (::minRelayTxFee.GetFeePerK() > HIGH_TX_FEE_PER_KB) { | ||||
InitWarning( | InitWarning( | ||||
AmountHighWarn("-minrelaytxfee") + " " + | AmountHighWarn("-minrelaytxfee") + " " + | ||||
_("The wallet will avoid paying less than the minimum relay fee.")); | _("The wallet will avoid paying less than the minimum relay fee.")); | ||||
} | } | ||||
if (IsArgSet("-mintxfee")) { | if (IsArgSet("-mintxfee")) { | ||||
Amount n = 0; | Amount n(0); | ||||
if (!ParseMoney(GetArg("-mintxfee", ""), n) || 0 == n) { | auto parsed = ParseMoney(GetArg("-mintxfee", ""), n); | ||||
if (!parsed || Amount(0) == n) { | |||||
return InitError(AmountErrMsg("mintxfee", GetArg("-mintxfee", ""))); | return InitError(AmountErrMsg("mintxfee", GetArg("-mintxfee", ""))); | ||||
} | } | ||||
if (n > HIGH_TX_FEE_PER_KB) { | if (n > HIGH_TX_FEE_PER_KB) { | ||||
InitWarning(AmountHighWarn("-mintxfee") + " " + | InitWarning(AmountHighWarn("-mintxfee") + " " + | ||||
_("This is the minimum transaction fee you pay on " | _("This is the minimum transaction fee you pay on " | ||||
"every transaction.")); | "every transaction.")); | ||||
} | } | ||||
CWallet::minTxFee = CFeeRate(n); | CWallet::minTxFee = CFeeRate(n); | ||||
} | } | ||||
if (IsArgSet("-fallbackfee")) { | if (IsArgSet("-fallbackfee")) { | ||||
Amount nFeePerK = 0; | Amount nFeePerK(0); | ||||
if (!ParseMoney(GetArg("-fallbackfee", ""), nFeePerK)) { | if (!ParseMoney(GetArg("-fallbackfee", ""), nFeePerK)) { | ||||
return InitError( | return InitError( | ||||
strprintf(_("Invalid amount for -fallbackfee=<amount>: '%s'"), | strprintf(_("Invalid amount for -fallbackfee=<amount>: '%s'"), | ||||
GetArg("-fallbackfee", ""))); | GetArg("-fallbackfee", ""))); | ||||
} | } | ||||
if (nFeePerK > HIGH_TX_FEE_PER_KB) { | if (nFeePerK > HIGH_TX_FEE_PER_KB) { | ||||
InitWarning(AmountHighWarn("-fallbackfee") + " " + | InitWarning(AmountHighWarn("-fallbackfee") + " " + | ||||
_("This is the transaction fee you may pay when fee " | _("This is the transaction fee you may pay when fee " | ||||
"estimates are not available.")); | "estimates are not available.")); | ||||
} | } | ||||
CWallet::fallbackFee = CFeeRate(nFeePerK); | CWallet::fallbackFee = CFeeRate(nFeePerK); | ||||
} | } | ||||
if (IsArgSet("-paytxfee")) { | if (IsArgSet("-paytxfee")) { | ||||
Amount nFeePerK = 0; | Amount nFeePerK(0); | ||||
if (!ParseMoney(GetArg("-paytxfee", ""), nFeePerK)) { | if (!ParseMoney(GetArg("-paytxfee", ""), nFeePerK)) { | ||||
return InitError(AmountErrMsg("paytxfee", GetArg("-paytxfee", ""))); | return InitError(AmountErrMsg("paytxfee", GetArg("-paytxfee", ""))); | ||||
} | } | ||||
if (nFeePerK > HIGH_TX_FEE_PER_KB) { | if (nFeePerK > HIGH_TX_FEE_PER_KB) { | ||||
InitWarning(AmountHighWarn("-paytxfee") + " " + | InitWarning(AmountHighWarn("-paytxfee") + " " + | ||||
_("This is the transaction fee you will pay if you " | _("This is the transaction fee you will pay if you " | ||||
"send a transaction.")); | "send a transaction.")); | ||||
} | } | ||||
payTxFee = CFeeRate(nFeePerK, 1000); | payTxFee = CFeeRate(nFeePerK, 1000); | ||||
if (payTxFee < ::minRelayTxFee) { | if (payTxFee < ::minRelayTxFee) { | ||||
return InitError( | return InitError( | ||||
strprintf(_("Invalid amount for -paytxfee=<amount>: '%s' (must " | strprintf(_("Invalid amount for -paytxfee=<amount>: '%s' (must " | ||||
"be at least %s)"), | "be at least %s)"), | ||||
GetArg("-paytxfee", ""), ::minRelayTxFee.ToString())); | GetArg("-paytxfee", ""), ::minRelayTxFee.ToString())); | ||||
} | } | ||||
} | } | ||||
if (IsArgSet("-maxtxfee")) { | if (IsArgSet("-maxtxfee")) { | ||||
Amount nMaxFee = 0; | Amount nMaxFee(0); | ||||
if (!ParseMoney(GetArg("-maxtxfee", ""), nMaxFee)) { | if (!ParseMoney(GetArg("-maxtxfee", ""), nMaxFee)) { | ||||
return InitError(AmountErrMsg("maxtxfee", GetArg("-maxtxfee", ""))); | return InitError(AmountErrMsg("maxtxfee", GetArg("-maxtxfee", ""))); | ||||
} | } | ||||
if (nMaxFee > HIGH_MAX_TX_FEE) { | if (nMaxFee > HIGH_MAX_TX_FEE) { | ||||
InitWarning(_("-maxtxfee is set very high! Fees this large could " | InitWarning(_("-maxtxfee is set very high! Fees this large could " | ||||
"be paid on a single transaction.")); | "be paid on a single transaction.")); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 138 Lines • Show Last 20 Lines |