// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "txdb.h"
+#include "txdb-leveldb.h"
#include "wallet.h"
#include "walletdb.h"
#include "crypter.h"
-#include "ui_interface.h"
+#include "interface.h"
#include "base58.h"
#include "kernel.h"
#include "coincontrol.h"
-#include <boost/algorithm/string/replace.hpp>
+#include "main.h"
+
#include <openssl/bio.h>
-#include "main.h"
+#include <random>
+#include <regex>
using namespace std;
extern int64_t nReserveBalance;
}
};
+const CWalletTx* CWallet::GetWalletTx(const uint256& hash) const
+{
+ LOCK(cs_wallet);
+ std::map<uint256, CWalletTx>::const_iterator it = mapWallet.find(hash);
+ if (it == mapWallet.end())
+ return NULL;
+ return &(it->second);
+}
+
CPubKey CWallet::GenerateNewKey()
{
bool fCompressed = CanSupportFeature(FEATURE_COMPRPUBKEY); // default to compressed public keys if we want 0.6.0 wallets
{
LOCK(cs_wallet);
- BOOST_FOREACH(const MasterKeyMap::value_type& pMasterKey, mapMasterKeys)
+ for (const MasterKeyMap::value_type& pMasterKey : mapMasterKeys)
{
if(!crypter.SetKeyFromPassphrase(strWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod))
return false;
CCrypter crypter;
CKeyingMaterial vMasterKey;
- BOOST_FOREACH(MasterKeyMap::value_type& pMasterKey, mapMasterKeys)
+ for (MasterKeyMap::value_type& pMasterKey : mapMasterKeys)
{
if(!crypter.SetKeyFromPassphrase(strOldWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod))
return false;
{
LOCK(cs_wallet);
- BOOST_FOREACH(const MasterKeyMap::value_type& pMasterKey, mapMasterKeys)
+ for (const MasterKeyMap::value_type& pMasterKey : mapMasterKeys)
{
if(!crypter.SetKeyFromPassphrase(strWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod))
return false;
return true;
}
-bool CWallet::GetPEM(const CKeyID &keyID, const std::string &fileName, const SecureString &strPassKey) const
-{
- BIO *pemOut = BIO_new_file(fileName.c_str(), "w");
- if (pemOut == NULL)
- return error("GetPEM() : failed to create file %s\n", fileName.c_str());
- CKey key;
- if (!GetKey(keyID, key))
- return error("GetPEM() : failed to get key for address=%s\n", CBitcoinAddress(keyID).ToString().c_str());
- bool result = key.WritePEM(pemOut, strPassKey);
- BIO_free(pemOut);
- return result;
-}
-
int64_t CWallet::IncOrderPosNext(CWalletDB *pwalletdb)
{
int64_t nRet = nOrderPosNext++;
// Note: maintaining indices in the database of (account,time) --> txid and (account, time) --> acentry
// would make this much faster for applications that do this a lot.
- for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
+ for (auto & it : mapWallet)
{
- CWalletTx* wtx = &((*it).second);
- txOrdered.insert(make_pair(wtx->nOrderPos, TxPair(wtx, (CAccountingEntry*)0)));
+ CWalletTx* wtx = &(it.second);
+ txOrdered.insert(make_pair(wtx->nOrderPos, TxPair(wtx, (CAccountingEntry*)nullptr)));
}
acentries.clear();
walletdb.ListAccountCreditDebit(strAccount, acentries);
- BOOST_FOREACH(CAccountingEntry& entry, acentries)
+ for (CAccountingEntry& entry : acentries)
{
- txOrdered.insert(make_pair(entry.nOrderPos, TxPair((CWalletTx*)0, &entry)));
+ txOrdered.insert(make_pair(entry.nOrderPos, TxPair((CWalletTx*)nullptr, &entry)));
}
return txOrdered;
// restored from backup or the user making copies of wallet.dat.
{
LOCK(cs_wallet);
- BOOST_FOREACH(const CTxIn& txin, tx.vin)
+ for (const CTxIn& txin : tx.vin)
{
map<uint256, CWalletTx>::iterator mi = mapWallet.find(txin.prevout.hash);
if (mi != mapWallet.end())
map<uint256, CWalletTx>::iterator mi = mapWallet.find(hash);
CWalletTx& wtx = (*mi).second;
- BOOST_FOREACH(const CTxOut& txout, tx.vout)
+ for (const CTxOut& txout : tx.vout)
{
if (IsMine(txout))
{
{
{
LOCK(cs_wallet);
- BOOST_FOREACH(PAIRTYPE(const uint256, CWalletTx)& item, mapWallet)
+ for (auto& item : mapWallet)
item.second.MarkDirty();
}
}
// If default receiving address gets used, replace it with a new one
CScript scriptDefaultKey;
scriptDefaultKey.SetDestination(vchDefaultKey.GetID());
- BOOST_FOREACH(const CTxOut& txout, wtx.vout)
+ for (const CTxOut& txout : wtx.vout)
{
if (txout.scriptPubKey == scriptDefaultKey)
{
std::string strCmd = GetArg("-walletnotify", "");
if ( !strCmd.empty())
- {
- boost::replace_all(strCmd, "%s", wtxIn.GetHash().GetHex());
- boost::thread t(runCommand, strCmd); // thread runs free
- }
+ // thread runs free
+ boost::thread t(runCommand, regex_replace(strCmd, static_cast<std::regex>("%s"), wtxIn.GetHash().GetHex()));
}
return true;
CWalletTx wtx(this,tx);
// Get merkle branch if transaction was found in a block
if (pblock)
- wtx.SetMerkleBranch(*pblock);
+ wtx.SetMerkleBranch(pblock);
return AddToWallet(wtx);
}
else
return MINE_NO;
}
+// marks certain txout's as spent
+// returns true if any update took place
+bool CWalletTx::UpdateSpent(const std::vector<char>& vfNewSpent)
+{
+ bool fReturn = false;
+ for (unsigned int i = 0; i < vfNewSpent.size(); i++)
+ {
+ if (i == vfSpent.size())
+ break;
+
+ if (vfNewSpent[i] && !vfSpent[i])
+ {
+ vfSpent[i] = true;
+ fReturn = true;
+ fAvailableCreditCached = fAvailableWatchCreditCached = false;
+ }
+ }
+ return fReturn;
+}
+
+// make sure balances are recalculated
+void CWalletTx::MarkDirty()
+{
+ fCreditCached = false;
+ fAvailableCreditCached = fAvailableWatchCreditCached = false;
+ fDebitCached = fWatchDebitCached = false;
+ fChangeCached = false;
+}
+
+void CWalletTx::BindWallet(CWallet *pwalletIn)
+{
+ pwallet = pwalletIn;
+ MarkDirty();
+}
+
+void CWalletTx::MarkSpent(unsigned int nOut)
+{
+ if (nOut >= vout.size())
+ throw std::runtime_error("CWalletTx::MarkSpent() : nOut out of range");
+ vfSpent.resize(vout.size());
+ if (!vfSpent[nOut])
+ {
+ vfSpent[nOut] = true;
+ fAvailableCreditCached = fAvailableWatchCreditCached = false;
+ }
+}
+
+void CWalletTx::MarkUnspent(unsigned int nOut)
+{
+ if (nOut >= vout.size())
+ throw std::runtime_error("CWalletTx::MarkUnspent() : nOut out of range");
+ vfSpent.resize(vout.size());
+ if (vfSpent[nOut])
+ {
+ vfSpent[nOut] = false;
+ fAvailableCreditCached = fAvailableWatchCreditCached = false;
+ }
+}
+
+bool CWalletTx::IsSpent(unsigned int nOut) const
+{
+ if (nOut >= vout.size())
+ throw std::runtime_error("CWalletTx::IsSpent() : nOut out of range");
+ if (nOut >= vfSpent.size())
+ return false;
+ return (!!vfSpent[nOut]);
+}
+
int64_t CWallet::GetDebit(const CTxIn &txin, const isminefilter& filter) const
{
{
return 0;
}
+isminetype CWallet::IsMine(const CTxOut& txout) const
+{
+ return ::IsMine(*this, txout.scriptPubKey);
+}
+
+int64_t CWallet::GetCredit(const CTxOut& txout, const isminefilter& filter) const
+{
+ if (!MoneyRange(txout.nValue))
+ throw std::runtime_error("CWallet::GetCredit() : value out of range");
+ return (IsMine(txout) & filter ? txout.nValue : 0);
+}
+
bool CWallet::IsChange(const CTxOut& txout) const
{
// TODO: fix handling of 'change' outputs. The assumption is that any
return false;
}
+int64_t CWallet::GetChange(const CTxOut& txout) const
+{
+ if (!MoneyRange(txout.nValue))
+ throw std::runtime_error("CWallet::GetChange() : value out of range");
+ return (IsChange(txout) ? txout.nValue : 0);
+}
+
+bool CWallet::IsMine(const CTransaction& tx) const
+{
+ for (const CTxOut& txout : tx.vout)
+ if (IsMine(txout) && txout.nValue >= nMinimumInputValue)
+ return true;
+ return false;
+}
+
+bool CWallet::IsFromMe(const CTransaction& tx) const
+{
+ return (GetDebit(tx, MINE_ALL) > 0);
+}
+
+int64_t CWallet::GetDebit(const CTransaction& tx, const isminefilter& filter) const
+{
+ int64_t nDebit = 0;
+ for (const CTxIn& txin : tx.vin)
+ {
+ nDebit += GetDebit(txin, filter);
+ if (!MoneyRange(nDebit))
+ throw std::runtime_error("CWallet::GetDebit() : value out of range");
+ }
+ return nDebit;
+}
+
+int64_t CWallet::GetCredit(const CTransaction& tx, const isminefilter& filter) const
+{
+ int64_t nCredit = 0;
+ for (const CTxOut& txout : tx.vout)
+ {
+ nCredit += GetCredit(txout, filter);
+ if (!MoneyRange(nCredit))
+ throw std::runtime_error("CWallet::GetCredit() : value out of range");
+ }
+ return nCredit;
+}
+
+int64_t CWallet::GetChange(const CTransaction& tx) const
+{
+ int64_t nChange = 0;
+ for (const CTxOut& txout : tx.vout)
+ {
+ nChange += GetChange(txout);
+ if (!MoneyRange(nChange))
+ throw std::runtime_error("CWallet::GetChange() : value out of range");
+ }
+ return nChange;
+}
+
int64_t CWalletTx::GetTxTime() const
{
return nTime;
return nRequests;
}
+bool CWalletTx::InMempool() const
+{
+ LOCK(mempool.cs);
+ if (mempool.exists(GetHash())) {
+ return true;
+ }
+ return false;
+}
+
+bool CWalletTx::IsTrusted() const
+{
+ // Quick answer in most cases
+ if (!IsFinal())
+ return false;
+ int nDepth = GetDepthInMainChain();
+ if (nDepth >= 1)
+ return true;
+ if (nDepth < 0)
+ return false;
+ if (!fConfChange || !IsFromMe(MINE_ALL)) // using wtx's cached debit
+ return false;
+
+ // Don't trust unconfirmed transactions from us unless they are in the mempool.
+ if (!InMempool())
+ return false;
+
+ // Trusted if all inputs are from us and are in the mempool:
+ for (const CTxIn& txin : vin)
+ {
+ // Transactions not sent by us: not trusted
+ const CWalletTx* parent = pwallet->GetWalletTx(txin.prevout.hash);
+ if (parent == NULL)
+ return false;
+ const CTxOut& parentOut = parent->vout[txin.prevout.n];
+ if (pwallet->IsMine(parentOut) != MINE_SPENDABLE)
+ return false;
+ }
+ return true;
+}
+
+int64_t CWalletTx::GetDebit(const isminefilter& filter) const
+{
+ if (vin.empty())
+ return 0;
+
+ int64_t nDebit = 0;
+ if (filter & MINE_SPENDABLE)
+ {
+ if (fDebitCached)
+ nDebit += nDebitCached;
+ else
+ {
+ nDebitCached = pwallet->GetDebit(*this, MINE_SPENDABLE);
+ fDebitCached = true;
+ nDebit += nDebitCached;
+ }
+ }
+ if (filter & MINE_WATCH_ONLY)
+ {
+ if (fWatchDebitCached)
+ nDebit += nWatchDebitCached;
+ else
+ {
+ nWatchDebitCached = pwallet->GetDebit(*this, MINE_WATCH_ONLY);
+ fWatchDebitCached = true;
+ nDebit += nWatchDebitCached;
+ }
+ }
+ return nDebit;
+}
+
+int64_t CWalletTx::GetCredit(const isminefilter& filter) const
+{
+ // Must wait until coinbase is safely deep enough in the chain before valuing it
+ if ((IsCoinBase() || IsCoinStake()) && GetBlocksToMaturity() > 0)
+ return 0;
+
+ int64_t credit = 0;
+ if (filter & MINE_SPENDABLE)
+ {
+ // GetBalance can assume transactions in mapWallet won't change
+ if (fCreditCached)
+ credit += nCreditCached;
+ else
+ {
+ nCreditCached = pwallet->GetCredit(*this, MINE_SPENDABLE);
+ fCreditCached = true;
+ credit += nCreditCached;
+ }
+ }
+ if (filter & MINE_WATCH_ONLY)
+ {
+ if (fWatchCreditCached)
+ credit += nWatchCreditCached;
+ else
+ {
+ nWatchCreditCached = pwallet->GetCredit(*this, MINE_WATCH_ONLY);
+ fWatchCreditCached = true;
+ credit += nWatchCreditCached;
+ }
+ }
+ return credit;
+}
+
+int64_t CWalletTx::GetImmatureCredit(bool fUseCache) const
+{
+ if (IsCoinBase() && GetBlocksToMaturity() > 0 && IsInMainChain())
+ {
+ if (fUseCache && fImmatureCreditCached)
+ return nImmatureCreditCached;
+ nImmatureCreditCached = pwallet->GetCredit(*this, MINE_SPENDABLE);
+ fImmatureCreditCached = true;
+ return nImmatureCreditCached;
+ }
+
+ return 0;
+}
+
+int64_t CWalletTx::GetImmatureWatchOnlyCredit(bool fUseCache) const
+{
+ if (IsCoinBase() && GetBlocksToMaturity() > 0 && IsInMainChain())
+ {
+ if (fUseCache && fImmatureWatchCreditCached)
+ return nImmatureWatchCreditCached;
+ nImmatureWatchCreditCached = pwallet->GetCredit(*this, MINE_WATCH_ONLY);
+ fImmatureWatchCreditCached = true;
+ return nImmatureWatchCreditCached;
+ }
+
+ return 0;
+}
+
+
+int64_t CWalletTx::GetAvailableCredit(bool fUseCache) const
+{
+ // Must wait until coinbase is safely deep enough in the chain before valuing it
+ if ((IsCoinBase() || IsCoinStake()) && GetBlocksToMaturity() > 0)
+ return 0;
+
+ if (fUseCache) {
+ if (fAvailableCreditCached)
+ return nAvailableCreditCached;
+ }
+
+ int64_t nCredit = 0;
+ for (unsigned int i = 0; i < vout.size(); i++)
+ {
+ if (!IsSpent(i))
+ {
+ const CTxOut &txout = vout[i];
+ nCredit += pwallet->GetCredit(txout, MINE_SPENDABLE);
+ if (!MoneyRange(nCredit))
+ throw std::runtime_error("CWalletTx::GetAvailableCredit() : value out of range");
+ }
+ }
+
+ nAvailableCreditCached = nCredit;
+ fAvailableCreditCached = true;
+
+ return nCredit;
+}
+
+int64_t CWalletTx::GetAvailableWatchCredit(bool fUseCache) const
+{
+ // Must wait until coinbase is safely deep enough in the chain before valuing it
+ if ((IsCoinBase() || IsCoinStake()) && GetBlocksToMaturity() > 0)
+ return 0;
+
+ if (fUseCache) {
+ if (fAvailableWatchCreditCached)
+ return nAvailableWatchCreditCached;
+ }
+
+ int64_t nCredit = 0;
+ for (unsigned int i = 0; i < vout.size(); i++)
+ {
+ if (!IsSpent(i))
+ {
+ const CTxOut &txout = vout[i];
+ nCredit += pwallet->GetCredit(txout, MINE_WATCH_ONLY);
+ if (!MoneyRange(nCredit))
+ throw std::runtime_error("CWalletTx::GetAvailableCredit() : value out of range");
+ }
+ }
+
+ nAvailableWatchCreditCached = nCredit;
+ fAvailableWatchCreditCached = true;
+
+ return nCredit;
+}
+
+int64_t CWalletTx::GetChange() const
+{
+ if (fChangeCached)
+ return nChangeCached;
+ nChangeCached = pwallet->GetChange(*this);
+ fChangeCached = true;
+ return nChangeCached;
+}
+
void CWalletTx::GetAmounts(int64_t& nGeneratedImmature, int64_t& nGeneratedMature, list<pair<CBitcoinAddress, int64_t> >& listReceived,
list<pair<CBitcoinAddress, int64_t> >& listSent, int64_t& nFee, string& strSentAccount, const isminefilter& filter) const
{
}
// Sent/received.
- BOOST_FOREACH(const CTxOut& txout, vout)
+ for (const CTxOut& txout : vout)
{
isminetype fIsMine = pwallet->IsMine(txout);
// Only need to handle txouts if AT LEAST one of these is true:
nGenerated = allGeneratedMature;
if (strAccount == strSentAccount)
{
- BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64_t)& s, listSent)
+ for (const auto& s : listSent)
nSent += s.second;
nFee = allFee;
}
{
LOCK(pwallet->cs_wallet);
- BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64_t)& r, listReceived)
+ for (const auto& r : listReceived)
{
if (pwallet->mapAddressBook.count(r.first))
{
if (SetMerkleBranch() < COPY_DEPTH)
{
vector<uint256> vWorkQueue;
- BOOST_FOREACH(const CTxIn& txin, vin)
+ for (const CTxIn& txin : vin)
vWorkQueue.push_back(txin.prevout.hash);
// This critsect is OK because txdb is already open
if (mi != pwallet->mapWallet.end())
{
tx = (*mi).second;
- BOOST_FOREACH(const CMerkleTx& txWalletPrev, (*mi).second.vtxPrev)
+ for (const CMerkleTx& txWalletPrev : (*mi).second.vtxPrev)
mapWalletPrev[txWalletPrev.GetHash()] = &txWalletPrev;
}
else if (mapWalletPrev.count(hash))
if (nDepth < COPY_DEPTH)
{
- BOOST_FOREACH(const CTxIn& txin, tx.vin)
+ for (const CTxIn& txin : tx.vin)
vWorkQueue.push_back(txin.prevout.hash);
}
}
{
CBlock block;
block.ReadFromDisk(pindex, true);
- BOOST_FOREACH(CTransaction& tx, block.vtx)
+ for (CTransaction& tx : block.vtx)
{
if (AddToWalletIfInvolvingMe(tx, &block, fUpdate))
ret++;
LOCK(cs_wallet);
fRepeat = false;
vector<CDiskTxPos> vMissingTx;
- BOOST_FOREACH(PAIRTYPE(const uint256, CWalletTx)& item, mapWallet)
+ for (auto& item : mapWallet)
{
CWalletTx& wtx = item.second;
if ((wtx.IsCoinBase() && wtx.IsSpent(0)) || (wtx.IsCoinStake() && wtx.IsSpent(1)))
}
}
-void CWalletTx::RelayWalletTransaction(CTxDB& txdb)
+bool CWalletTx::RelayWalletTransaction(CTxDB& txdb)
{
- BOOST_FOREACH(const CMerkleTx& tx, vtxPrev)
- {
- if (!(tx.IsCoinBase() || tx.IsCoinStake()))
- {
- uint256 hash = tx.GetHash();
- if (!txdb.ContainsTx(hash))
- RelayTransaction((CTransaction)tx, hash);
- }
- }
- if (!(IsCoinBase() || IsCoinStake()))
+ uint256 hash = GetHash();
+ if (IsCoinBase() || IsCoinStake() || txdb.ContainsTx(hash) || !InMempool())
+ return false;
+
+ for(std::vector<CMerkleTx>::const_iterator it = vtxPrev.begin(); it != vtxPrev.end(); it++)
{
- uint256 hash = GetHash();
+ const CMerkleTx& tx = *it;
+ uint256 hash = tx.GetHash();
+
+ if (tx.IsCoinBase() || tx.IsCoinStake())
+ continue;
+
if (!txdb.ContainsTx(hash))
- {
- printf("Relaying wtx %s\n", hash.ToString().substr(0,10).c_str());
- RelayTransaction((CTransaction)*this, hash);
- }
+ RelayTransaction((CTransaction)tx, hash);
}
+
+ printf("Relaying wtx %s\n", hash.ToString().substr(0,10).c_str());
+ RelayTransaction((CTransaction)*this, hash);
+ return true;
}
-void CWalletTx::RelayWalletTransaction()
+bool CWalletTx::RelayWalletTransaction()
{
CTxDB txdb("r");
- RelayWalletTransaction(txdb);
+ return RelayWalletTransaction(txdb);
}
-void CWallet::ResendWalletTransactions(bool fForceResend)
+std::vector<uint256> CWallet::ResendWalletTransactionsBefore(int64_t nTime)
{
- if (!fForceResend) {
- // Do this infrequently and randomly to avoid giving away
- // that these are our transactions.
- static int64_t nNextTime = GetRand(GetTime() + 30 * 60);
- if (GetTime() < nNextTime)
- return;
- bool fFirst = (nNextTime == 0);
- nNextTime = GetTime() + GetRand(30 * 60);
- if (fFirst)
- return;
+ std::vector<uint256> result;
- // Only do it if there's been a new block since last time
- static int64_t nLastTime = 0;
- if (nTimeBestReceived < nLastTime)
- return;
- nLastTime = GetTime();
+ LOCK(cs_wallet);
+ // Sort them in chronological order
+ map<unsigned int, CWalletTx*> mapSorted;
+ for (auto& item : mapWallet)
+ {
+ CWalletTx& wtx = item.second;
+ // Don't rebroadcast if newer than nTime:
+ if (wtx.nTimeReceived > nTime)
+ continue;
+ mapSorted.insert(make_pair(wtx.nTimeReceived, &wtx));
}
-
- // Rebroadcast any of our txes that aren't in a block yet
- printf("ResendWalletTransactions()\n");
- CTxDB txdb("r");
+ for (auto& item : mapSorted)
{
- LOCK(cs_wallet);
- // Sort them in chronological order
- multimap<unsigned int, CWalletTx*> mapSorted;
- BOOST_FOREACH(PAIRTYPE(const uint256, CWalletTx)& item, mapWallet)
- {
- CWalletTx& wtx = item.second;
- // Don't rebroadcast until it's had plenty of time that
- // it should have gotten in already by now.
- if (fForceResend || nTimeBestReceived - (int64_t)wtx.nTimeReceived > 5 * 60)
- mapSorted.insert(make_pair(wtx.nTimeReceived, &wtx));
- }
- BOOST_FOREACH(PAIRTYPE(const unsigned int, CWalletTx*)& item, mapSorted)
- {
- CWalletTx& wtx = *item.second;
- if (wtx.CheckTransaction())
- wtx.RelayWalletTransaction(txdb);
- else
- printf("ResendWalletTransactions() : CheckTransaction failed for transaction %s\n", wtx.GetHash().ToString().c_str());
- }
+ CWalletTx& wtx = *item.second;
+ if (wtx.RelayWalletTransaction())
+ result.push_back(wtx.GetHash());
}
+ return result;
}
+void CWallet::ResendWalletTransactions(int64_t nBestBlockTime)
+{
+ int64_t nNow = GetTime();
+ // Do this infrequently and randomly to avoid giving away
+ // that these are our transactions.
+ if (nNow < nNextResend)
+ return;
+ bool fFirst = (nNextResend == 0);
+ nNextResend = PoissonNextSend(nNow, 5*60);
+ if (fFirst)
+ return;
+ // Only do it if there's been a new block since last time
+ if (nBestBlockTime < nLastResend)
+ return;
+ nLastResend = nNow;
+ // Rebroadcast unconfirmed txes older than 5 minutes before the last
+ // block was found:
+ std::vector<uint256> relayed = ResendWalletTransactionsBefore(nBestBlockTime - 5*60);
+ if (!relayed.empty())
+ printf("CWallet::ResendWalletTransactions: rebroadcast %" PRIszu " unconfirmed transactions\n", relayed.size());
+}
//////////////////////////////////////////////////////////////////////////////
vector<pair<int64_t, pair<const CWalletTx*,unsigned int> > > vValue;
int64_t nTotalLower = 0;
- random_shuffle(vCoins.begin(), vCoins.end(), GetRandInt);
+ std::random_device rd;
+ std::mt19937 g(rd());
+ shuffle(vCoins.begin(), vCoins.end(), g);
- BOOST_FOREACH(const COutput &output, vCoins)
+ for (const COutput &output : vCoins)
{
if (!output.fSpendable)
continue;
}
// Solve subset sum by stochastic approximation
- sort(vValue.rbegin(), vValue.rend(), CompareValueOnly());
+ std::sort(vValue.begin(), vValue.end(), CompareValueOnly());
+ std::reverse(vValue.begin(), vValue.end());
vector<char> vfBest;
int64_t nBest;
// coin control -> return all selected outputs (we want all selected to go into the transaction for sure)
if (coinControl && coinControl->HasSelected())
{
- BOOST_FOREACH(const COutput& out, vCoins)
+ for (const COutput& out : vCoins)
{
if(!out.fSpendable)
continue;
setCoinsRet.clear();
nValueRet = 0;
- BOOST_FOREACH(COutput output, vCoins)
+ for (COutput output : vCoins)
{
if(!output.fSpendable)
continue;
bool CWallet::CreateTransaction(const vector<pair<CScript, int64_t> >& vecSend, CWalletTx& wtxNew, CReserveKey& reservekey, int64_t& nFeeRet, const CCoinControl* coinControl)
{
int64_t nValue = 0;
- BOOST_FOREACH (const PAIRTYPE(CScript, int64_t)& s, vecSend)
+ for (const auto& s : vecSend)
{
if (nValue < 0)
return false;
int64_t nTotalValue = nValue + nFeeRet;
double dPriority = 0;
// vouts to the payees
- BOOST_FOREACH (const PAIRTYPE(CScript, int64_t)& s, vecSend)
+ for (const auto& s : vecSend)
wtxNew.vout.push_back(CTxOut(s.second, s.first));
// Choose coins to use
int64_t nValueIn = 0;
if (!SelectCoins(nTotalValue, wtxNew.nTime, setCoins, nValueIn, coinControl))
return false;
- BOOST_FOREACH(PAIRTYPE(const CWalletTx*, unsigned int) pcoin, setCoins)
+ for (auto pcoin : setCoins)
{
int64_t nCredit = pcoin.first->vout[pcoin.second].nValue;
dPriority += (double)nCredit * pcoin.first->GetDepthInMainChain();
reservekey.ReturnKey();
// Fill vin
- BOOST_FOREACH(const PAIRTYPE(const CWalletTx*,unsigned int)& coin, setCoins)
+ for (const auto& coin : setCoins)
wtxNew.vin.push_back(CTxIn(coin.first->GetHash(),coin.second));
// Sign
int nIn = 0;
- BOOST_FOREACH(const PAIRTYPE(const CWalletTx*,unsigned int)& coin, setCoins)
+ for (const auto& coin : setCoins)
if (!SignSignature(*this, *coin.first, wtxNew, nIn++))
return false;
wtxNew.vout.push_back(CTxOut(0, scriptOutput));
double dWeight = 0;
- BOOST_FOREACH(PAIRTYPE(const CWalletTx*, unsigned int) pcoin, setCoins)
+ for (auto pcoin : setCoins)
{
int64_t nCredit = pcoin.first->vout[pcoin.second].nValue;
if (wtxNew.vout[0].nValue > 0) {
int64_t nBytes = ::GetSerializeSize(*(CTransaction*)&wtxNew, SER_NETWORK, PROTOCOL_VERSION) + wtxNew.vin.size() * 110;
- double dFinalPriority = dWeight /= nBytes;
+ double dFinalPriority = dWeight / nBytes;
bool fAllowFree = CTransaction::AllowFree(dFinalPriority);
// Get actual transaction fee according to its size and priority
// Sign
int nIn = 0;
- BOOST_FOREACH(const CWalletTx* pcoin, vwtxPrev)
+ for (const CWalletTx* pcoin : vwtxPrev)
{
if (!SignSignature(*this, *pcoin, txNew, nIn++))
return error("CreateCoinStake : failed to sign coinstake\n");
AddToWallet(wtxNew);
// Mark old coins as spent
- BOOST_FOREACH(const CTxIn& txin, wtxNew.vin)
+ for (const CTxIn& txin : wtxNew.vin)
{
CWalletTx &coin = mapWallet[txin.prevout.hash];
coin.BindWallet(this);
{
LOCK(cs_wallet);
CWalletDB walletdb(strWalletFile);
- BOOST_FOREACH(int64_t nIndex, setKeyPool)
+ for (int64_t nIndex : setKeyPool)
walletdb.ErasePool(nIndex);
setKeyPool.clear();
{
LOCK(cs_wallet);
- BOOST_FOREACH(PAIRTYPE(uint256, CWalletTx) walletEntry, mapWallet)
+ for (auto walletEntry : mapWallet)
{
CWalletTx *pcoin = &walletEntry.second;
set< set<CBitcoinAddress> > groupings;
set<CBitcoinAddress> grouping;
- BOOST_FOREACH(PAIRTYPE(uint256, CWalletTx) walletEntry, mapWallet)
+ for (auto& walletEntry : mapWallet)
{
CWalletTx *pcoin = &walletEntry.second;
- if (pcoin->vin.size() > 0 && IsMine(pcoin->vin[0]))
+ if (pcoin->vin.size() > 0)
{
+ bool any_mine = false;
// group all input addresses with each other
- BOOST_FOREACH(CTxIn txin, pcoin->vin)
+ for (CTxIn txin : pcoin->vin)
{
CBitcoinAddress address;
+ if(!IsMine(txin)) // If this input isn't mine, ignore it
+ continue;
if(!ExtractAddress(*this, mapWallet[txin.prevout.hash].vout[txin.prevout.n].scriptPubKey, address))
continue;
grouping.insert(address);
+ any_mine = true;
}
// group change with input addresses
- BOOST_FOREACH(CTxOut txout, pcoin->vout)
+ if (any_mine)
+ {
+ for (CTxOut txout : pcoin->vout)
if (IsChange(txout))
{
- CWalletTx tx = mapWallet[pcoin->vin[0].prevout.hash];
CBitcoinAddress txoutAddr;
if(!ExtractAddress(*this, txout.scriptPubKey, txoutAddr))
continue;
grouping.insert(txoutAddr);
}
- groupings.insert(grouping);
- grouping.clear();
+ }
+ if (!grouping.empty())
+ {
+ groupings.insert(grouping);
+ grouping.clear();
+ }
}
// group lone addrs by themselves
set< set<CBitcoinAddress>* > uniqueGroupings; // a set of pointers to groups of addresses
map< CBitcoinAddress, set<CBitcoinAddress>* > setmap; // map addresses to the unique group containing it
- BOOST_FOREACH(set<CBitcoinAddress> grouping, groupings)
+ for (set<CBitcoinAddress> grouping : groupings)
{
// make a set of all the groups hit by this new group
set< set<CBitcoinAddress>* > hits;
map< CBitcoinAddress, set<CBitcoinAddress>* >::iterator it;
- BOOST_FOREACH(CBitcoinAddress address, grouping)
+ for (CBitcoinAddress address : grouping)
if ((it = setmap.find(address)) != setmap.end())
hits.insert((*it).second);
// merge all hit groups into a new single group and delete old groups
set<CBitcoinAddress>* merged = new set<CBitcoinAddress>(grouping);
- BOOST_FOREACH(set<CBitcoinAddress>* hit, hits)
+ for (set<CBitcoinAddress>* hit : hits)
{
merged->insert(hit->begin(), hit->end());
uniqueGroupings.erase(hit);
uniqueGroupings.insert(merged);
// update setmap
- BOOST_FOREACH(CBitcoinAddress element, *merged)
+ for (CBitcoinAddress element : *merged)
setmap[element] = merged;
}
set< set<CBitcoinAddress> > ret;
- BOOST_FOREACH(set<CBitcoinAddress>* uniqueGrouping, uniqueGroupings)
+ for (set<CBitcoinAddress>* uniqueGrouping : uniqueGroupings)
{
ret.insert(*uniqueGrouping);
delete uniqueGrouping;
vCoins.push_back(&(*it).second);
CTxDB txdb("r");
- BOOST_FOREACH(CWalletTx* pcoin, vCoins)
+ for (CWalletTx* pcoin : vCoins)
{
// Find the corresponding transaction index
CTxIndex txindex;
return; // only disconnecting coinstake requires marking input unspent
LOCK(cs_wallet);
- BOOST_FOREACH(const CTxIn& txin, tx.vin)
+ for (const CTxIn& txin : tx.vin)
{
map<uint256, CWalletTx>::iterator mi = mapWallet.find(txin.prevout.hash);
if (mi != mapWallet.end())
CWalletDB walletdb(strWalletFile);
LOCK2(cs_main, cs_wallet);
- BOOST_FOREACH(const int64_t& id, setKeyPool)
+ for (const int64_t& id : setKeyPool)
{
CKeyPool keypool;
if (!walletdb.ReadPool(id, keypool))