X-Git-Url: https://git.novaco.in/?a=blobdiff_plain;f=src%2Fwallet.cpp;h=2455b272488ca34727b73fc80b801bdc2a7f4f34;hb=HEAD;hp=b484ab6ec93f37b60a099182fdc7517ed7e967c4;hpb=81aaaf43084ca0b9473e7a85e6833301cba09c30;p=novacoin.git diff --git a/src/wallet.cpp b/src/wallet.cpp index b484ab6..83cb307 100644 --- a/src/wallet.cpp +++ b/src/wallet.cpp @@ -3,19 +3,21 @@ // 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 "wallet.h" -#include "walletdb.h" -#include "crypter.h" -#include "ui_interface.h" +#include "txdb-leveldb.h" #include "base58.h" -#include "kernel.h" #include "coincontrol.h" -#include +#include "crypter.h" +#include "kernel.h" +#include "random.h" +#include "walletdb.h" + +#include + +#include +#include -#include "main.h" -using namespace std; extern int64_t nReserveBalance; ////////////////////////////////////////////////////////////////////////////// @@ -25,13 +27,22 @@ extern int64_t nReserveBalance; struct CompareValueOnly { - bool operator()(const pair >& t1, - const pair >& t2) const + bool operator()(const std::pair >& t1, + const std::pair >& t2) const { return t1.first < t2.first; } }; +const CWalletTx* CWallet::GetWalletTx(const uint256& hash) const +{ + LOCK(cs_wallet); + std::map::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 @@ -74,8 +85,8 @@ CMalleableKeyView CWallet::GenerateNewMalleableKey() if (!nTimeFirstKey || nCreationTime < nTimeFirstKey) nTimeFirstKey = nCreationTime; - if (!AddMalleableKey(mKey)) - throw std::runtime_error("CWallet::GenerateNewMalleableKey() : AddMalleableKey failed"); + if (!AddKey(mKey)) + throw std::runtime_error("CWallet::GenerateNewMalleableKey() : AddKey failed"); return CMalleableKeyView(mKey); } @@ -91,7 +102,7 @@ bool CWallet::AddKey(const CKey& key) return true; } -bool CWallet::AddMalleableKey(const CMalleableKey& mKey) +bool CWallet::AddKey(const CMalleableKey& mKey) { CMalleableKeyView keyView = CMalleableKeyView(mKey); CSecret vchSecretH = mKey.GetSecretH(); @@ -124,7 +135,9 @@ bool CWallet::AddCryptedMalleableKey(const CMalleableKeyView& keyView, const std return true; } -bool CWallet::AddCryptedKey(const CPubKey &vchPubKey, const vector &vchCryptedSecret) +bool CWallet::LoadCryptedKey(const CPubKey &vchPubKey, const std::vector &vchCryptedSecret) { SetMinVersion(FEATURE_WALLETCRYPT); return CCryptoKeyStore::AddCryptedKey(vchPubKey, vchCryptedSecret); } + +bool CWallet::AddCryptedKey(const CPubKey &vchPubKey, const std::vector &vchCryptedSecret) { if (!CCryptoKeyStore::AddCryptedKey(vchPubKey, vchCryptedSecret)) return false; @@ -166,6 +179,12 @@ bool CWallet::LoadKeyMetadata(const CMalleableKeyView &keyView, const CKeyMetada return true; } +bool CWallet::LoadKey(const CMalleableKeyView &keyView, const CSecret &vchSecretH) { return CCryptoKeyStore::AddMalleableKey(keyView, vchSecretH); } + +bool CWallet::LoadCryptedKey(const CMalleableKeyView &keyView, const std::vector &vchCryptedSecretH) { return CCryptoKeyStore::AddCryptedMalleableKey(keyView, vchCryptedSecretH); } + +bool CWallet::LoadMinVersion(int nVersion) { nWalletVersion = nVersion; nWalletMaxVersion = std::max(nWalletMaxVersion, nVersion); return true; } + bool CWallet::AddCScript(const CScript& redeemScript) { if (!CCryptoKeyStore::AddCScript(redeemScript)) @@ -236,7 +255,7 @@ bool CWallet::Unlock(const SecureString& strWalletPassphrase) { 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; @@ -259,7 +278,7 @@ bool CWallet::ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase, 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; @@ -361,13 +380,13 @@ bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase) RandAddSeedPerfmon(); vMasterKey.resize(WALLET_CRYPTO_KEY_SIZE); - RAND_bytes(&vMasterKey[0], WALLET_CRYPTO_KEY_SIZE); + GetRandBytes(&vMasterKey[0], WALLET_CRYPTO_KEY_SIZE); CMasterKey kMasterKey; RandAddSeedPerfmon(); kMasterKey.vchSalt.resize(WALLET_CRYPTO_SALT_SIZE); - RAND_bytes(&kMasterKey.vchSalt[0], WALLET_CRYPTO_SALT_SIZE); + GetRandBytes(&kMasterKey.vchSalt[0], WALLET_CRYPTO_SALT_SIZE); CCrypter crypter; int64_t nStartTime = GetTimeMillis(); @@ -445,7 +464,7 @@ bool CWallet::DecryptWallet(const SecureString& strWalletPassphrase) { 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; @@ -536,16 +555,16 @@ CWallet::TxItems CWallet::OrderedTxItems(std::list& acentries, // 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::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(std::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(std::make_pair(entry.nOrderPos, TxPair((CWalletTx*)nullptr, &entry))); } return txOrdered; @@ -558,9 +577,9 @@ void CWallet::WalletUpdateSpent(const CTransaction &tx, bool fBlock) // 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::iterator mi = mapWallet.find(txin.prevout.hash); + auto mi = mapWallet.find(txin.prevout.hash); if (mi != mapWallet.end()) { CWalletTx& wtx = (*mi).second; @@ -580,10 +599,10 @@ void CWallet::WalletUpdateSpent(const CTransaction &tx, bool fBlock) if (fBlock) { uint256 hash = tx.GetHash(); - map::iterator mi = mapWallet.find(hash); + auto mi = mapWallet.find(hash); CWalletTx& wtx = (*mi).second; - BOOST_FOREACH(const CTxOut& txout, tx.vout) + for (const CTxOut& txout : tx.vout) { if (IsMine(txout)) { @@ -602,7 +621,7 @@ void CWallet::MarkDirty() { { LOCK(cs_wallet); - BOOST_FOREACH(PAIRTYPE(const uint256, CWalletTx)& item, mapWallet) + for (auto& item : mapWallet) item.second.MarkDirty(); } } @@ -613,7 +632,7 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn) { LOCK(cs_wallet); // Inserts only if not already there, returns tx inserted or tx found - pair::iterator, bool> ret = mapWallet.insert(make_pair(hash, wtxIn)); + auto ret = mapWallet.insert(std::make_pair(hash, wtxIn)); CWalletTx& wtx = (*ret.first).second; wtx.BindWallet(this); bool fInsertedNew = ret.second; @@ -703,7 +722,7 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn) // 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) { @@ -726,10 +745,8 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn) 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("%s"), wtxIn.GetHash().GetHex())); } return true; @@ -738,7 +755,7 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn) // Add a transaction to the wallet, or update it. // pblock is optional, but should be provided if the transaction is known to be in a block. // If fUpdate is true, existing transactions will be updated. -bool CWallet::AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pblock, bool fUpdate, bool fFindBlock) +bool CWallet::AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pblock, bool fUpdate) { uint256 hash = tx.GetHash(); { @@ -776,7 +793,7 @@ isminetype CWallet::IsMine(const CTxIn &txin) const { { LOCK(cs_wallet); - map::const_iterator mi = mapWallet.find(txin.prevout.hash); + auto mi = mapWallet.find(txin.prevout.hash); if (mi != mapWallet.end()) { const CWalletTx& prev = (*mi).second; @@ -787,11 +804,79 @@ isminetype CWallet::IsMine(const CTxIn &txin) const return MINE_NO; } +// marks certain txout's as spent +// returns true if any update took place +bool CWalletTx::UpdateSpent(const std::vector& 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 { { LOCK(cs_wallet); - map::const_iterator mi = mapWallet.find(txin.prevout.hash); + auto mi = mapWallet.find(txin.prevout.hash); if (mi != mapWallet.end()) { const CWalletTx& prev = (*mi).second; @@ -803,6 +888,18 @@ 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 @@ -825,6 +922,62 @@ bool CWallet::IsChange(const CTxOut& txout) const 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; @@ -841,7 +994,7 @@ int CWalletTx::GetRequestCount() const // Generated block if (hashBlock != 0) { - map::const_iterator mi = pwallet->mapRequestCount.find(hashBlock); + auto mi = pwallet->mapRequestCount.find(hashBlock); if (mi != pwallet->mapRequestCount.end()) nRequests = (*mi).second; } @@ -849,7 +1002,7 @@ int CWalletTx::GetRequestCount() const else { // Did anyone request this transaction? - map::const_iterator mi = pwallet->mapRequestCount.find(GetHash()); + auto mi = pwallet->mapRequestCount.find(GetHash()); if (mi != pwallet->mapRequestCount.end()) { nRequests = (*mi).second; @@ -857,7 +1010,7 @@ int CWalletTx::GetRequestCount() const // How about the block it's in? if (nRequests == 0 && hashBlock != 0) { - map::const_iterator mi = pwallet->mapRequestCount.find(hashBlock); + auto mi = pwallet->mapRequestCount.find(hashBlock); if (mi != pwallet->mapRequestCount.end()) nRequests = (*mi).second; else @@ -869,8 +1022,208 @@ int CWalletTx::GetRequestCount() const return nRequests; } -void CWalletTx::GetAmounts(int64_t& nGeneratedImmature, int64_t& nGeneratedMature, list >& listReceived, - list >& listSent, int64_t& nFee, string& strSentAccount, const isminefilter& filter) const +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, std::list >& listReceived, + std::list >& listSent, int64_t& nFee, std::string& strSentAccount, const isminefilter& filter) const { nGeneratedImmature = nGeneratedMature = nFee = 0; listReceived.clear(); @@ -895,7 +1248,7 @@ void CWalletTx::GetAmounts(int64_t& nGeneratedImmature, int64_t& nGeneratedMatur } // 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: @@ -921,42 +1274,42 @@ void CWalletTx::GetAmounts(int64_t& nGeneratedImmature, int64_t& nGeneratedMatur // If we are debited by the transaction, add the output as a "sent" entry if (nDebit > 0) - listSent.push_back(make_pair(address, txout.nValue)); + listSent.push_back(std::make_pair(address, txout.nValue)); // If we are receiving the output, add it as a "received" entry if (fIsMine & filter) - listReceived.push_back(make_pair(address, txout.nValue)); + listReceived.push_back(std::make_pair(address, txout.nValue)); } } -void CWalletTx::GetAccountAmounts(const string& strAccount, int64_t& nGenerated, int64_t& nReceived, +void CWalletTx::GetAccountAmounts(const std::string& strAccount, int64_t& nGenerated, int64_t& nReceived, int64_t& nSent, int64_t& nFee, const isminefilter& filter) const { nGenerated = nReceived = nSent = nFee = 0; int64_t allGeneratedImmature, allGeneratedMature, allFee; allGeneratedImmature = allGeneratedMature = allFee = 0; - string strSentAccount; - list > listReceived; - list > listSent; + std::string strSentAccount; + std::list > listReceived; + std::list > listSent; GetAmounts(allGeneratedImmature, allGeneratedMature, listReceived, listSent, allFee, strSentAccount, filter); - if (strAccount == "") + if (strAccount.empty()) 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)) { - map::const_iterator mi = pwallet->mapAddressBook.find(r.first); + auto mi = pwallet->mapAddressBook.find(r.first); if (mi != pwallet->mapAddressBook.end() && (*mi).second == strAccount) nReceived += r.second; } @@ -968,6 +1321,11 @@ void CWalletTx::GetAccountAmounts(const string& strAccount, int64_t& nGenerated, } } +bool CWalletTx::IsFromMe(const isminefilter &filter) const +{ + return (GetDebit(filter) > 0); +} + void CWalletTx::AddSupportingTransactions(CTxDB& txdb) { vtxPrev.clear(); @@ -975,15 +1333,15 @@ void CWalletTx::AddSupportingTransactions(CTxDB& txdb) const int COPY_DEPTH = 3; if (SetMerkleBranch() < COPY_DEPTH) { - vector vWorkQueue; - BOOST_FOREACH(const CTxIn& txin, vin) + std::vector vWorkQueue; + for (const CTxIn& txin : vin) vWorkQueue.push_back(txin.prevout.hash); // This critsect is OK because txdb is already open { LOCK(pwallet->cs_wallet); - map mapWalletPrev; - set setAlreadyDone; + std::map mapWalletPrev; + std::set setAlreadyDone; for (unsigned int i = 0; i < vWorkQueue.size(); i++) { uint256 hash = vWorkQueue[i]; @@ -992,11 +1350,11 @@ void CWalletTx::AddSupportingTransactions(CTxDB& txdb) setAlreadyDone.insert(hash); CMerkleTx tx; - map::const_iterator mi = pwallet->mapWallet.find(hash); + auto mi = pwallet->mapWallet.find(hash); 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)) @@ -1018,7 +1376,7 @@ void CWalletTx::AddSupportingTransactions(CTxDB& txdb) if (nDepth < COPY_DEPTH) { - BOOST_FOREACH(const CTxIn& txin, tx.vin) + for (const CTxIn& txin : tx.vin) vWorkQueue.push_back(txin.prevout.hash); } } @@ -1028,6 +1386,32 @@ void CWalletTx::AddSupportingTransactions(CTxDB& txdb) reverse(vtxPrev.begin(), vtxPrev.end()); } +bool CWalletTx::AcceptWalletTransaction(CTxDB& txdb, bool fCheckInputs) +{ + + { + LOCK(mempool.cs); + // Add previous supporting transactions first + for (CMerkleTx& tx : vtxPrev) + { + if (!(tx.IsCoinBase() || tx.IsCoinStake())) + { + uint256 hash = tx.GetHash(); + if (!mempool.exists(hash) && !txdb.ContainsTx(hash)) + tx.AcceptToMemoryPool(txdb, fCheckInputs); + } + } + return AcceptToMemoryPool(txdb, fCheckInputs); + } + return false; +} + +bool CWalletTx::AcceptWalletTransaction() +{ + CTxDB txdb("r"); + return AcceptWalletTransaction(txdb); +} + bool CWalletTx::WriteToDisk() { return CWalletDB(pwallet->strWalletFile).WriteTx(GetHash(), *this); @@ -1047,7 +1431,7 @@ int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate) { CBlock block; block.ReadFromDisk(pindex, true); - BOOST_FOREACH(CTransaction& tx, block.vtx) + for (CTransaction& tx : block.vtx) { if (AddToWalletIfInvolvingMe(tx, &block, fUpdate)) ret++; @@ -1062,7 +1446,7 @@ int CWallet::ScanForWalletTransaction(const uint256& hashTx) { CTransaction tx; tx.ReadFromDisk(COutPoint(hashTx, 0)); - if (AddToWalletIfInvolvingMe(tx, NULL, true, true)) + if (AddToWalletIfInvolvingMe(tx, NULL, true)) return 1; return 0; } @@ -1075,8 +1459,8 @@ void CWallet::ReacceptWalletTransactions() { LOCK(cs_wallet); fRepeat = false; - vector vMissingTx; - BOOST_FOREACH(PAIRTYPE(const uint256, CWalletTx)& item, mapWallet) + std::vector vMissingTx; + for (auto& item : mapWallet) { CWalletTx& wtx = item.second; if ((wtx.IsCoinBase() && wtx.IsSpent(0)) || (wtx.IsCoinStake() && wtx.IsSpent(1))) @@ -1126,83 +1510,83 @@ void CWallet::ReacceptWalletTransactions() } } -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::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 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 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 + std::map mapSorted; + for (auto& item : mapWallet) + { + CWalletTx& wtx = item.second; + // Don't rebroadcast if newer than nTime: + if (wtx.nTimeReceived > nTime) + continue; + mapSorted.insert(std::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 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 relayed = ResendWalletTransactionsBefore(nBestBlockTime - 5*60); + if (!relayed.empty()) + printf("CWallet::ResendWalletTransactions: rebroadcast %" PRIszu " unconfirmed transactions\n", relayed.size()); +} ////////////////////////////////////////////////////////////////////////////// @@ -1216,7 +1600,7 @@ int64_t CWallet::GetBalance() const int64_t nTotal = 0; { LOCK(cs_wallet); - for (map::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) + for (auto it = mapWallet.begin(); it != mapWallet.end(); ++it) { const CWalletTx* pcoin = &(*it).second; if (pcoin->IsTrusted()) @@ -1232,7 +1616,7 @@ int64_t CWallet::GetWatchOnlyBalance() const int64_t nTotal = 0; { LOCK(cs_wallet); - for (map::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) + for (auto it = mapWallet.begin(); it != mapWallet.end(); ++it) { const CWalletTx* pcoin = &(*it).second; if (pcoin->IsTrusted()) @@ -1248,7 +1632,7 @@ int64_t CWallet::GetUnconfirmedBalance() const int64_t nTotal = 0; { LOCK(cs_wallet); - for (map::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) + for (auto it = mapWallet.begin(); it != mapWallet.end(); ++it) { const CWalletTx* pcoin = &(*it).second; if (!pcoin->IsFinal() || !pcoin->IsTrusted()) @@ -1263,7 +1647,7 @@ int64_t CWallet::GetUnconfirmedWatchOnlyBalance() const int64_t nTotal = 0; { LOCK(cs_wallet); - for (map::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) + for (auto it = mapWallet.begin(); it != mapWallet.end(); ++it) { const CWalletTx* pcoin = &(*it).second; if (!pcoin->IsFinal() || !pcoin->IsTrusted()) @@ -1278,7 +1662,7 @@ int64_t CWallet::GetImmatureBalance() const int64_t nTotal = 0; { LOCK(cs_wallet); - for (map::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) + for (auto it = mapWallet.begin(); it != mapWallet.end(); ++it) { const CWalletTx* pcoin = &(*it).second; nTotal += pcoin->GetImmatureCredit(); @@ -1292,7 +1676,7 @@ int64_t CWallet::GetImmatureWatchOnlyBalance() const int64_t nTotal = 0; { LOCK(cs_wallet); - for (map::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) + for (auto it = mapWallet.begin(); it != mapWallet.end(); ++it) { const CWalletTx* pcoin = &(*it).second; nTotal += pcoin->GetImmatureWatchOnlyCredit(); @@ -1302,13 +1686,13 @@ int64_t CWallet::GetImmatureWatchOnlyBalance() const } // populate vCoins with vector of spendable COutputs -void CWallet::AvailableCoins(vector& vCoins, bool fOnlyConfirmed, const CCoinControl *coinControl) const +void CWallet::AvailableCoins(std::vector& vCoins, bool fOnlyConfirmed, const CCoinControl *coinControl) const { vCoins.clear(); { LOCK(cs_wallet); - for (map::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) + for (auto it = mapWallet.begin(); it != mapWallet.end(); ++it) { const CWalletTx* pcoin = &(*it).second; @@ -1337,13 +1721,13 @@ void CWallet::AvailableCoins(vector& vCoins, bool fOnlyConfirmed, const } } -void CWallet::AvailableCoinsMinConf(vector& vCoins, int nConf, int64_t nMinValue, int64_t nMaxValue) const +void CWallet::AvailableCoinsMinConf(std::vector& vCoins, int nConf, int64_t nMinValue, int64_t nMaxValue) const { vCoins.clear(); { LOCK(cs_wallet); - for (map::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) + for (auto it = mapWallet.begin(); it != mapWallet.end(); ++it) { const CWalletTx* pcoin = &(*it).second; @@ -1368,10 +1752,10 @@ void CWallet::AvailableCoinsMinConf(vector& vCoins, int nConf, int64_t } } -static void ApproximateBestSubset(vector > >vValue, int64_t nTotalLower, int64_t nTargetValue, - vector& vfBest, int64_t& nBest, int iterations = 1000) +static void ApproximateBestSubset(std::vector > >vValue, int64_t nTotalLower, int64_t nTargetValue, + std::vector& vfBest, int64_t& nBest, int iterations = 1000) { - vector vfIncluded; + std::vector vfIncluded; vfBest.assign(vValue.size(), true); nBest = nTotalLower; @@ -1410,7 +1794,7 @@ int64_t CWallet::GetStake() const { int64_t nTotal = 0; LOCK(cs_wallet); - for (map::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) + for (auto it = mapWallet.begin(); it != mapWallet.end(); ++it) { const CWalletTx* pcoin = &(*it).second; if (pcoin->IsCoinStake() && pcoin->GetBlocksToMaturity() > 0 && pcoin->GetDepthInMainChain() > 0) @@ -1423,7 +1807,7 @@ int64_t CWallet::GetWatchOnlyStake() const { int64_t nTotal = 0; LOCK(cs_wallet); - for (map::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) + for (auto it = mapWallet.begin(); it != mapWallet.end(); ++it) { const CWalletTx* pcoin = &(*it).second; if (pcoin->IsCoinStake() && pcoin->GetBlocksToMaturity() > 0 && pcoin->GetDepthInMainChain() > 0) @@ -1436,7 +1820,7 @@ int64_t CWallet::GetNewMint() const { int64_t nTotal = 0; LOCK(cs_wallet); - for (map::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) + for (auto it = mapWallet.begin(); it != mapWallet.end(); ++it) { const CWalletTx* pcoin = &(*it).second; if (pcoin->IsCoinBase() && pcoin->GetBlocksToMaturity() > 0 && pcoin->GetDepthInMainChain() > 0) @@ -1449,7 +1833,7 @@ int64_t CWallet::GetWatchOnlyNewMint() const { int64_t nTotal = 0; LOCK(cs_wallet); - for (map::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) + for (auto it = mapWallet.begin(); it != mapWallet.end(); ++it) { const CWalletTx* pcoin = &(*it).second; if (pcoin->IsCoinBase() && pcoin->GetBlocksToMaturity() > 0 && pcoin->GetDepthInMainChain() > 0) @@ -1458,21 +1842,23 @@ int64_t CWallet::GetWatchOnlyNewMint() const return nTotal; } -bool CWallet::SelectCoinsMinConf(int64_t nTargetValue, unsigned int nSpendTime, int nConfMine, int nConfTheirs, vector vCoins, set >& setCoinsRet, int64_t& nValueRet) const +bool CWallet::SelectCoinsMinConf(int64_t nTargetValue, unsigned int nSpendTime, int nConfMine, int nConfTheirs, std::vector vCoins, std::set >& setCoinsRet, int64_t& nValueRet) const { setCoinsRet.clear(); nValueRet = 0; // List of values less than target - pair > coinLowestLarger; + std::pair > coinLowestLarger; coinLowestLarger.first = std::numeric_limits::max(); coinLowestLarger.second.first = NULL; - vector > > vValue; + std::vector > > 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; @@ -1490,7 +1876,7 @@ bool CWallet::SelectCoinsMinConf(int64_t nTargetValue, unsigned int nSpendTime, int64_t n = pcoin->vout[i].nValue; - pair > coin = make_pair(n,make_pair(pcoin, i)); + auto coin = std::make_pair(n, std::make_pair(pcoin, i)); if (n == nTargetValue) { @@ -1529,8 +1915,9 @@ bool CWallet::SelectCoinsMinConf(int64_t nTargetValue, unsigned int nSpendTime, } // Solve subset sum by stochastic approximation - sort(vValue.rbegin(), vValue.rend(), CompareValueOnly()); - vector vfBest; + std::sort(vValue.begin(), vValue.end(), CompareValueOnly()); + std::reverse(vValue.begin(), vValue.end()); + std::vector vfBest; int64_t nBest; ApproximateBestSubset(vValue, nTotalLower, nTargetValue, vfBest, nBest, 1000); @@ -1567,20 +1954,20 @@ bool CWallet::SelectCoinsMinConf(int64_t nTargetValue, unsigned int nSpendTime, return true; } -bool CWallet::SelectCoins(int64_t nTargetValue, unsigned int nSpendTime, set >& setCoinsRet, int64_t& nValueRet, const CCoinControl* coinControl) const +bool CWallet::SelectCoins(int64_t nTargetValue, unsigned int nSpendTime, std::set >& setCoinsRet, int64_t& nValueRet, const CCoinControl* coinControl) const { - vector vCoins; + std::vector vCoins; AvailableCoins(vCoins, true, coinControl); // 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; nValueRet += out.tx->vout[out.i].nValue; - setCoinsRet.insert(make_pair(out.tx, out.i)); + setCoinsRet.insert(std::make_pair(out.tx, out.i)); } return (nValueRet >= nTargetValue); } @@ -1590,16 +1977,45 @@ bool CWallet::SelectCoins(int64_t nTargetValue, unsigned int nSpendTime, set >& setCoinsRet, int64_t& nValueRet) const +bool CWallet::SelectCoinsSimple(int64_t nTargetValue, int64_t nMinValue, int64_t nMaxValue, unsigned int nSpendTime, int nMinConf, std::set >& setCoinsRet, int64_t& nValueRet) const { - vector vCoins; + std::vector vCoins; AvailableCoinsMinConf(vCoins, nMinConf, nMinValue, nMaxValue); setCoinsRet.clear(); nValueRet = 0; - BOOST_FOREACH(COutput output, vCoins) + for (COutput output : vCoins) { if(!output.fSpendable) continue; @@ -1620,7 +2036,7 @@ bool CWallet::SelectCoinsSimple(int64_t nTargetValue, int64_t nMinValue, int64_t int64_t n = pcoin->vout[i].nValue; - pair > coin = make_pair(n,make_pair(pcoin, i)); + auto coin = std::make_pair(n, std::make_pair(pcoin, i)); if (n >= nTargetValue) { @@ -1640,10 +2056,10 @@ bool CWallet::SelectCoinsSimple(int64_t nTargetValue, int64_t nMinValue, int64_t return true; } -bool CWallet::CreateTransaction(const vector >& vecSend, CWalletTx& wtxNew, CReserveKey& reservekey, int64_t& nFeeRet, const CCoinControl* coinControl) +bool CWallet::CreateTransaction(const std::vector >& 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; @@ -1660,7 +2076,7 @@ bool CWallet::CreateTransaction(const vector >& vecSend, CTxDB txdb("r"); { nFeeRet = nTransactionFee; - while (true) + for ( ; ; ) { wtxNew.vin.clear(); wtxNew.vout.clear(); @@ -1669,15 +2085,15 @@ bool CWallet::CreateTransaction(const vector >& vecSend, 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 - set > setCoins; + std::set > setCoins; 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(); @@ -1712,19 +2128,19 @@ bool CWallet::CreateTransaction(const vector >& vecSend, } // Insert change txn at random position: - vector::iterator position = wtxNew.vout.begin()+GetRandInt(wtxNew.vout.size()); + auto position = wtxNew.vout.begin()+GetRandInt(wtxNew.vout.size()); wtxNew.vout.insert(position, CTxOut(nChange, scriptChange)); } else 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; @@ -1739,9 +2155,9 @@ bool CWallet::CreateTransaction(const vector >& vecSend, int64_t nPayFee = nTransactionFee * (1 + (int64_t)nBytes / 1000); int64_t nMinFee = wtxNew.GetMinFee(1, fAllowFree, GMF_SEND, nBytes); - if (nFeeRet < max(nPayFee, nMinFee)) + if (nFeeRet < std::max(nPayFee, nMinFee)) { - nFeeRet = max(nPayFee, nMinFee); + nFeeRet = std::max(nPayFee, nMinFee); continue; } @@ -1758,8 +2174,8 @@ bool CWallet::CreateTransaction(const vector >& vecSend, bool CWallet::CreateTransaction(CScript scriptPubKey, int64_t nValue, CWalletTx& wtxNew, CReserveKey& reservekey, int64_t& nFeeRet, const CCoinControl* coinControl) { - vector< pair > vecSend; - vecSend.push_back(make_pair(scriptPubKey, nValue)); + std::vector< std::pair > vecSend; + vecSend.push_back(std::make_pair(scriptPubKey, nValue)); return CreateTransaction(vecSend, wtxNew, reservekey, nFeeRet, coinControl); } @@ -1778,7 +2194,7 @@ void CWallet::GetStakeWeightFromValue(const int64_t& nTime, const int64_t& nValu nWeight = bnCoinDayWeight.getuint64(); } -bool CWallet::MergeCoins(const int64_t& nAmount, const int64_t& nMinValue, const int64_t& nOutputValue, list& listMerged) +bool CWallet::MergeCoins(const int64_t& nAmount, const int64_t& nMinValue, const int64_t& nOutputValue, std::list& listMerged) { int64_t nBalance = GetBalance(); @@ -1787,7 +2203,7 @@ bool CWallet::MergeCoins(const int64_t& nAmount, const int64_t& nMinValue, const listMerged.clear(); int64_t nValueIn = 0; - set > setCoins; + std::set > setCoins; // Simple coins selection - no randomization if (!SelectCoinsSimple(nAmount, nMinValue, nOutputValue, GetTime(), 1, setCoins, nValueIn)) @@ -1797,7 +2213,7 @@ bool CWallet::MergeCoins(const int64_t& nAmount, const int64_t& nMinValue, const return false; CWalletTx wtxNew; - vector vwtxPrev; + std::vector vwtxPrev; // Reserve a new key pair from key pool CReserveKey reservekey(this); @@ -1811,7 +2227,7 @@ bool CWallet::MergeCoins(const int64_t& nAmount, const int64_t& nMinValue, const 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; @@ -1872,7 +2288,7 @@ bool CWallet::MergeCoins(const int64_t& nAmount, const int64_t& nMinValue, const 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 @@ -1907,7 +2323,7 @@ bool CWallet::CreateCoinStake(uint256 &hashTx, uint32_t nOut, uint32_t nGenerati if (!GetTransaction(hashTx, wtx)) return error("Transaction %s is not found\n", hashTx.GetHex().c_str()); - vector vSolutions; + std::vector vSolutions; txnouttype whichType; CScript scriptPubKeyOut; CScript scriptPubKeyKernel = wtx.vout[nOut].scriptPubKey; @@ -1949,7 +2365,7 @@ bool CWallet::CreateCoinStake(uint256 &hashTx, uint32_t nOut, uint32_t nGenerati txNew.vout.clear(); // List of constake dependencies - vector vwtxPrev; + std::vector vwtxPrev; vwtxPrev.push_back(&wtx); // Set generation time, and kernel input @@ -2048,7 +2464,7 @@ bool CWallet::CreateCoinStake(uint256 &hashTx, uint32_t nOut, uint32_t nGenerati nCredit += GetProofOfStakeReward(nCoinAge, nBits, nGenerationTime); int64_t nMinFee = 0; - while (true) + for ( ; ; ) { // Set output amount if (fDontSplitCoins) @@ -2061,7 +2477,7 @@ bool CWallet::CreateCoinStake(uint256 &hashTx, uint32_t nOut, uint32_t nGenerati // 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"); @@ -2125,7 +2541,7 @@ bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey) 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); @@ -2145,7 +2561,7 @@ bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey) -string CWallet::SendMoney(CScript scriptPubKey, int64_t nValue, CWalletTx& wtxNew, bool fAskFee) +std::string CWallet::SendMoney(CScript scriptPubKey, int64_t nValue, CWalletTx& wtxNew, bool fAskFee) { // Check amount if (nValue <= 0) @@ -2158,19 +2574,19 @@ string CWallet::SendMoney(CScript scriptPubKey, int64_t nValue, CWalletTx& wtxNe if (IsLocked()) { - string strError = _("Error: Wallet locked, unable to create transaction "); + std::string strError = _("Error: Wallet locked, unable to create transaction "); printf("SendMoney() : %s", strError.c_str()); return strError; } if (fWalletUnlockMintOnly) { - string strError = _("Error: Wallet unlocked for block minting only, unable to create transaction."); + std::string strError = _("Error: Wallet unlocked for block minting only, unable to create transaction."); printf("SendMoney() : %s", strError.c_str()); return strError; } if (!CreateTransaction(scriptPubKey, nValue, wtxNew, reservekey, nFeeRequired)) { - string strError; + std::string strError; if (nValue + nFeeRequired > GetBalance()) strError = strprintf(_("Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds "), FormatMoney(nFeeRequired).c_str()); else @@ -2236,14 +2652,14 @@ DBErrors CWallet::ZapWalletTx() return DB_LOAD_OK; } -bool CWallet::SetAddressBookName(const CTxDestination& address, const string& strName) +bool CWallet::SetAddressBookName(const CTxDestination& address, const std::string& strName) { return SetAddressBookName(CBitcoinAddress(address), strName); } -bool CWallet::SetAddressBookName(const CBitcoinAddress& address, const string& strName) +bool CWallet::SetAddressBookName(const CBitcoinAddress& address, const std::string& strName) { - std::map::iterator mi = mapAddressBook.find(address); + auto mi = mapAddressBook.find(address); mapAddressBook[address] = strName; NotifyAddressBookChanged(this, address, strName, ::IsMine(*this, address) != MINE_NO, (mi == mapAddressBook.end()) ? CT_NEW : CT_UPDATED); if (!fFileBacked) @@ -2279,11 +2695,26 @@ void CWallet::PrintWallet(const CBlock& block) printf("\n"); } +void CWallet::Inventory(const uint256 &hash) +{ + { + LOCK(cs_wallet); + auto mi = mapRequestCount.find(hash); + if (mi != mapRequestCount.end()) + (*mi).second++; + } +} + +unsigned int CWallet::GetKeyPoolSize() +{ + return (unsigned int)(setKeyPool.size()); +} + bool CWallet::GetTransaction(const uint256 &hashTx, CWalletTx& wtx) { { LOCK(cs_wallet); - map::iterator mi = mapWallet.find(hashTx); + auto mi = mapWallet.find(hashTx); if (mi != mapWallet.end()) { wtx = (*mi).second; @@ -2304,7 +2735,7 @@ bool CWallet::SetDefaultKey(const CPubKey &vchPubKey) return true; } -bool GetWalletFile(CWallet* pwallet, string &strWalletFileOut) +bool GetWalletFile(CWallet* pwallet, std::string &strWalletFileOut) { if (!pwallet->fFileBacked) return false; @@ -2321,7 +2752,7 @@ bool CWallet::NewKeyPool(unsigned int nSize) { LOCK(cs_wallet); CWalletDB walletdb(strWalletFile); - BOOST_FOREACH(int64_t nIndex, setKeyPool) + for (int64_t nIndex : setKeyPool) walletdb.ErasePool(nIndex); setKeyPool.clear(); @@ -2332,7 +2763,7 @@ bool CWallet::NewKeyPool(unsigned int nSize) if (nSize > 0) nKeys = nSize; else - nKeys = max(GetArg("-keypool", 100), 0); + nKeys = std::max(GetArg("-keypool", 100), 0); for (uint64_t i = 0; i < nKeys; i++) { @@ -2360,7 +2791,7 @@ bool CWallet::TopUpKeyPool(unsigned int nSize) if (nSize > 0) nTargetSize = nSize; else - nTargetSize = max(GetArg("-keypool", 100), 0); + nTargetSize = std::max(GetArg("-keypool", 100), 0); while (setKeyPool.size() < (nTargetSize + 1)) { @@ -2368,7 +2799,7 @@ bool CWallet::TopUpKeyPool(unsigned int nSize) if (!setKeyPool.empty()) nEnd = *(--setKeyPool.end()) + 1; if (!walletdb.WritePool(nEnd, CKeyPool(GenerateNewKey()))) - throw runtime_error("TopUpKeyPool() : writing generated key failed"); + throw std::runtime_error("TopUpKeyPool() : writing generated key failed"); setKeyPool.insert(nEnd); printf("keypool added key %" PRIu64 ", size=%" PRIszu "\n", nEnd, setKeyPool.size()); } @@ -2395,9 +2826,9 @@ void CWallet::ReserveKeyFromKeyPool(int64_t& nIndex, CKeyPool& keypool) nIndex = *(setKeyPool.begin()); setKeyPool.erase(setKeyPool.begin()); if (!walletdb.ReadPool(nIndex, keypool)) - throw runtime_error("ReserveKeyFromKeyPool() : read failed"); + throw std::runtime_error("ReserveKeyFromKeyPool() : read failed"); if (!HaveKey(keypool.vchPubKey.GetID())) - throw runtime_error("ReserveKeyFromKeyPool() : unknown key in key pool"); + throw std::runtime_error("ReserveKeyFromKeyPool() : unknown key in key pool"); assert(keypool.vchPubKey.IsValid()); if (fDebug && GetBoolArg("-printkeypool")) printf("keypool reserve %" PRId64 "\n", nIndex); @@ -2412,7 +2843,7 @@ int64_t CWallet::AddReserveKey(const CKeyPool& keypool) int64_t nIndex = 1 + *(--setKeyPool.end()); if (!walletdb.WritePool(nIndex, keypool)) - throw runtime_error("AddReserveKey() : writing added key failed"); + throw std::runtime_error("AddReserveKey() : writing added key failed"); setKeyPool.insert(nIndex); return nIndex; } @@ -2479,11 +2910,11 @@ int64_t CWallet::GetOldestKeyPoolTime() std::map CWallet::GetAddressBalances() { - map balances; + std::map balances; { LOCK(cs_wallet); - BOOST_FOREACH(PAIRTYPE(uint256, CWalletTx) walletEntry, mapWallet) + for (auto walletEntry : mapWallet) { CWalletTx *pcoin = &walletEntry.second; @@ -2517,38 +2948,47 @@ std::map CWallet::GetAddressBalances() return balances; } -set< set > CWallet::GetAddressGroupings() +std::set< std::set > CWallet::GetAddressGroupings() { - set< set > groupings; - set grouping; + std::set< std::set > groupings; + std::set 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 @@ -2564,20 +3004,20 @@ set< set > CWallet::GetAddressGroupings() } } - set< set* > uniqueGroupings; // a set of pointers to groups of addresses - map< CBitcoinAddress, set* > setmap; // map addresses to the unique group containing it - BOOST_FOREACH(set grouping, groupings) + std::set< std::set* > uniqueGroupings; // a set of pointers to groups of addresses + std::map< CBitcoinAddress, std::set* > setmap; // map addresses to the unique group containing it + for (std::set grouping : groupings) { // make a set of all the groups hit by this new group - set< set* > hits; - map< CBitcoinAddress, set* >::iterator it; - BOOST_FOREACH(CBitcoinAddress address, grouping) + std::set< std::set* > hits; + std::map< CBitcoinAddress, std::set* >::iterator it; + 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* merged = new set(grouping); - BOOST_FOREACH(set* hit, hits) + std::set* merged = new std::set(grouping); + for (std::set* hit : hits) { merged->insert(hit->begin(), hit->end()); uniqueGroupings.erase(hit); @@ -2586,12 +3026,12 @@ set< set > CWallet::GetAddressGroupings() uniqueGroupings.insert(merged); // update setmap - BOOST_FOREACH(CBitcoinAddress element, *merged) + for (CBitcoinAddress element : *merged) setmap[element] = merged; } - set< set > ret; - BOOST_FOREACH(set* uniqueGrouping, uniqueGroupings) + std::set< std::set > ret; + for (std::set* uniqueGrouping : uniqueGroupings) { ret.insert(*uniqueGrouping); delete uniqueGrouping; @@ -2608,13 +3048,13 @@ void CWallet::FixSpentCoins(int& nMismatchFound, int64_t& nBalanceInQuestion, bo nBalanceInQuestion = 0; LOCK(cs_wallet); - vector vCoins; + std::vector vCoins; vCoins.reserve(mapWallet.size()); - for (map::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) + for (auto it = mapWallet.begin(); it != mapWallet.end(); ++it) vCoins.push_back(&(*it).second); CTxDB txdb("r"); - BOOST_FOREACH(CWalletTx* pcoin, vCoins) + for (CWalletTx* pcoin : vCoins) { // Find the corresponding transaction index CTxIndex txindex; @@ -2667,9 +3107,9 @@ void CWallet::DisableTransaction(const CTransaction &tx) 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::iterator mi = mapWallet.find(txin.prevout.hash); + auto mi = mapWallet.find(txin.prevout.hash); if (mi != mapWallet.end()) { CWalletTx& prev = (*mi).second; @@ -2708,6 +3148,18 @@ void CReserveKey::KeepKey() vchPubKey = CPubKey(); } +CReserveKey::CReserveKey(CWallet *pwalletIn) +{ + nIndex = -1; + pwallet = pwalletIn; +} + +CReserveKey::~CReserveKey() +{ + if (!fShutdown) + ReturnKey(); +} + void CReserveKey::ReturnKey() { if (nIndex != -1) @@ -2716,22 +3168,22 @@ void CReserveKey::ReturnKey() vchPubKey = CPubKey(); } -void CWallet::GetAllReserveKeys(set& setAddress) const +void CWallet::GetAllReserveKeys(std::set& setAddress) const { setAddress.clear(); 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)) - throw runtime_error("GetAllReserveKeyHashes() : read failed"); + throw std::runtime_error("GetAllReserveKeyHashes() : read failed"); assert(keypool.vchPubKey.IsValid()); CKeyID keyID = keypool.vchPubKey.GetID(); if (!HaveKey(keyID)) - throw runtime_error("GetAllReserveKeyHashes() : unknown key in key pool"); + throw std::runtime_error("GetAllReserveKeyHashes() : unknown key in key pool"); setAddress.insert(keyID); } } @@ -2741,7 +3193,7 @@ void CWallet::UpdatedTransaction(const uint256 &hashTx) { LOCK(cs_wallet); // Only notify UI if this transaction is in this wallet - map::const_iterator mi = mapWallet.find(hashTx); + auto mi = mapWallet.find(hashTx); if (mi != mapWallet.end()) { NotifyTransactionChanged(this, hashTx, CT_UPDATED); @@ -2777,7 +3229,7 @@ void CWallet::GetAddresses(std::map &mapAddresses) con std::vector vAffected; ::ExtractAffectedKeys(*this, out.scriptPubKey, vAffected); - for(std::vector::const_iterator it3 = vAffected.begin(); it3 != vAffected.end(); it3++) { + for(auto it3 = vAffected.begin(); it3 != vAffected.end(); it3++) { CBitcoinAddress addrAffected(*it3); if (mapAddresses.find(addrAffected) != mapAddresses.end() && (mapAddresses[addrAffected] == 0 || mapAddresses[addrAffected] > wtx.nTime)) mapAddresses[addrAffected] = wtx.nTime; @@ -2790,10 +3242,10 @@ void CWallet::GetAddresses(std::map &mapAddresses) con void CWallet::ClearOrphans() { - list orphans; + std::list orphans; LOCK(cs_wallet); - for(map::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) + for(auto it = mapWallet.begin(); it != mapWallet.end(); ++it) { const CWalletTx *wtx = &(*it).second; if((wtx->IsCoinBase() || wtx->IsCoinStake()) && !wtx->IsInMainChain()) @@ -2802,7 +3254,112 @@ void CWallet::ClearOrphans() } } - for(list::const_iterator it = orphans.begin(); it != orphans.end(); ++it) + for(auto it = orphans.begin(); it != orphans.end(); ++it) EraseFromWallet(*it); } + +CWalletTx::CWalletTx() +{ + Init(nullptr); +} + +CWalletTx::CWalletTx(const CWallet *pwalletIn) +{ + Init(pwalletIn); +} + +CWalletTx::CWalletTx(const CWallet *pwalletIn, const CMerkleTx &txIn) : CMerkleTx(txIn) +{ + Init(pwalletIn); +} + +CWalletTx::CWalletTx(const CWallet *pwalletIn, const CTransaction &txIn) : CMerkleTx(txIn) +{ + Init(pwalletIn); +} + +void CWalletTx::Init(const CWallet *pwalletIn) +{ + pwallet = pwalletIn; + vtxPrev.clear(); + mapValue.clear(); + vOrderForm.clear(); + fTimeReceivedIsTxTime = false; + nTimeReceived = 0; + nTimeSmart = 0; + fFromMe = false; + strFromAccount.clear(); + vfSpent.clear(); + fDebitCached = false; + fWatchDebitCached = false; + fCreditCached = false; + fWatchCreditCached = false; + fAvailableCreditCached = false; + fAvailableWatchCreditCached = false; + fImmatureCreditCached = false; + fImmatureWatchCreditCached = false; + fChangeCached = false; + nDebitCached = 0; + nWatchDebitCached = 0; + nCreditCached = 0; + nWatchCreditCached = 0; + nAvailableCreditCached = 0; + nAvailableWatchCreditCached = 0; + nImmatureCreditCached = 0; + nImmatureWatchCreditCached = 0; + nChangeCached = 0; + nOrderPos = -1; +} + +COutput::COutput(const CWalletTx *txIn, int iIn, int nDepthIn, bool fSpendableIn) +{ + tx = txIn; i = iIn; nDepth = nDepthIn; fSpendable = fSpendableIn; +} + +std::string COutput::ToString() const +{ + return strprintf("COutput(%s, %d, %d, %d) [%s]", tx->GetHash().ToString().substr(0,10).c_str(), i, fSpendable, nDepth, FormatMoney(tx->vout[i].nValue).c_str()); +} + +CAccount::CAccount() +{ + SetNull(); +} + +void CAccount::SetNull() +{ + vchPubKey = CPubKey(); +} + +CAccountingEntry::CAccountingEntry() +{ + SetNull(); +} + +void CAccountingEntry::SetNull() +{ + nCreditDebit = 0; + nTime = 0; + strAccount.clear(); + strOtherAccount.clear(); + strComment.clear(); + nOrderPos = -1; +} + +CWalletKey::CWalletKey(int64_t nExpires) +{ + nTimeCreated = (nExpires ? GetTime() : 0); + nTimeExpires = nExpires; +} + +CKeyPool::CKeyPool() +{ + nTime = GetTime(); +} + +CKeyPool::CKeyPool(const CPubKey &vchPubKeyIn) +{ + nTime = GetTime(); + vchPubKey = vchPubKeyIn; +}