Remove useless inline
[novacoin.git] / src / wallet.cpp
index e039091..9baa959 100644 (file)
@@ -3,6 +3,8 @@
 // Distributed under the MIT/X11 software license, see the accompanying
 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
 
+#include <regex>
+
 #include "txdb.h"
 #include "wallet.h"
 #include "walletdb.h"
@@ -11,7 +13,6 @@
 #include "base58.h"
 #include "kernel.h"
 #include "coincontrol.h"
-#include <boost/algorithm/string/replace.hpp>
 #include <openssl/bio.h>
 
 #include "main.h"
@@ -24,6 +25,35 @@ extern int64_t nReserveBalance;
 // mapWallet
 //
 
+CWallet::CWallet()
+{
+    SetNull();
+}
+
+CWallet::CWallet(std::string strWalletFileIn)
+{
+    SetNull();
+
+    strWalletFile = strWalletFileIn;
+    fFileBacked = true;
+}
+
+void CWallet::SetNull()
+{
+    nWalletVersion = FEATURE_BASE;
+    nWalletMaxVersion = FEATURE_BASE;
+    fFileBacked = false;
+    nMasterKeyMaxID = 0;
+    pwalletdbEncryption = NULL;
+    pwalletdbDecryption = NULL;
+    nNextResend = 0;
+    nLastResend = 0;
+    nOrderPosNext = 0;
+    nKernelsTried = 0;
+    nCoinDaysTried = 0;
+    nTimeFirstKey = 0;
+}
+
 struct CompareValueOnly
 {
     bool operator()(const pair<int64_t, pair<const CWalletTx*, unsigned int> >& t1,
@@ -176,6 +206,13 @@ bool CWallet::LoadKeyMetadata(const CMalleableKeyView &keyView, const CKeyMetada
     return true;
 }
 
+bool CWallet::LoadMinVersion(int nVersion)
+{
+    nWalletVersion = nVersion;
+    nWalletMaxVersion = max(nWalletMaxVersion, nVersion);
+    return true;
+}
+
 bool CWallet::AddCScript(const CScript& redeemScript)
 {
     if (!CCryptoKeyStore::AddCScript(redeemScript))
@@ -748,11 +785,9 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn)
         // notify an external script when a wallet transaction comes in or is updated
         auto strCmd = GetArg("-walletnotify", "");
 
-        if ( !strCmd.empty())
-        {
-            boost::replace_all(strCmd, "%s", wtxIn.GetHash().GetHex());
-            boost::thread t(runCommand, strCmd); // thread runs free
-        }
+        if (!strCmd.empty())
+            // thread runs free
+            boost::thread t(runCommand, regex_replace(strCmd, static_cast<regex>("%s"), wtxIn.GetHash().GetHex()));
 
     }
     return true;
@@ -810,6 +845,60 @@ isminetype CWallet::IsMine(const CTxIn &txin) const
     return MINE_NO;
 }
 
+
+CWalletTx::CWalletTx()
+{
+    Init(NULL);
+}
+
+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;
+}
+
 // marks certain txout's as spent
 // returns true if any update took place
 bool CWalletTx::UpdateSpent(const vector<char>& vfNewSpent)
@@ -950,38 +1039,41 @@ bool CWallet::IsFromMe(const CTransaction& tx) const
 
 int64_t CWallet::GetDebit(const CTransaction& tx, const isminefilter& filter) const
 {
-    int64_t nDebit = 0;
+    CBigNum nDebit = 0;
     for(const CTxIn& txin :  tx.vin)
     {
-        nDebit += GetDebit(txin, filter);
-        if (!MoneyRange(nDebit))
+        auto nValue = GetDebit(txin, filter);
+        nDebit += nValue;
+        if (!MoneyRange(nValue) || !MoneyRange(nDebit))
             throw runtime_error("CWallet::GetDebit() : value out of range");
     }
-    return nDebit;
+    return nDebit.getint64();
 }
 
 int64_t CWallet::GetCredit(const CTransaction& tx, const isminefilter& filter) const
 {
-    int64_t nCredit = 0;
+    CBigNum nCredit = 0;
     for(const CTxOut& txout :  tx.vout)
     {
-        nCredit += GetCredit(txout, filter);
-        if (!MoneyRange(nCredit))
+        auto nValue = GetCredit(txout, filter);
+        nCredit += nValue;
+        if (!MoneyRange(nValue) || !MoneyRange(nCredit))
             throw runtime_error("CWallet::GetCredit() : value out of range");
     }
-    return nCredit;
+    return nCredit.getint64();
 }
 
 int64_t CWallet::GetChange(const CTransaction& tx) const
 {
-    int64_t nChange = 0;
+    CBigNum nChange = 0;
     for(const CTxOut& txout :  tx.vout)
     {
-        nChange += GetChange(txout);
-        if (!MoneyRange(nChange))
+        int64_t nValue = GetChange(txout);
+        nChange += nValue;
+        if (!MoneyRange(nValue) || !MoneyRange(nChange))
             throw runtime_error("CWallet::GetChange() : value out of range");
     }
-    return nChange;
+    return nChange.getint64();
 }
 
 int64_t CWalletTx::GetTxTime() const
@@ -1172,22 +1264,23 @@ int64_t CWalletTx::GetAvailableCredit(bool fUseCache) const
             return nAvailableCreditCached;
     }
 
-    int64_t nCredit = 0;
-    for (unsigned int i = 0; i < vout.size(); i++)
+    CBigNum nCredit = 0;
+    for (uint32_t i = 0; i < vout.size(); i++)
     {
         if (!IsSpent(i))
         {
             const CTxOut &txout = vout[i];
-            nCredit += pwallet->GetCredit(txout, MINE_SPENDABLE);
-            if (!MoneyRange(nCredit))
+            int64_t nValue = pwallet->GetCredit(txout, MINE_SPENDABLE);
+            nCredit += nValue;
+            if (!MoneyRange(nValue) || !MoneyRange(nCredit))
                 throw runtime_error("CWalletTx::GetAvailableCredit() : value out of range");
         }
     }
 
-    nAvailableCreditCached = nCredit;
+    nAvailableCreditCached = nCredit.getint64();
     fAvailableCreditCached = true;
 
-    return nCredit;
+    return nCredit.getint64();
 }
 
 int64_t CWalletTx::GetAvailableWatchCredit(bool fUseCache) const
@@ -1201,22 +1294,23 @@ int64_t CWalletTx::GetAvailableWatchCredit(bool fUseCache) const
             return nAvailableWatchCreditCached;
     }
 
-    int64_t nCredit = 0;
+    CBigNum 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))
+            int64_t nValue = pwallet->GetCredit(txout, MINE_WATCH_ONLY);
+            nCredit += nValue;
+            if (!MoneyRange(nValue) || !MoneyRange(nCredit))
                 throw runtime_error("CWalletTx::GetAvailableCredit() : value out of range");
         }
     }
 
-    nAvailableWatchCreditCached = nCredit;
+    nAvailableWatchCreditCached = nCredit.getint64();
     fAvailableWatchCreditCached = true;
 
-    return nCredit;
+    return nCredit.getint64();
 }
 
 int64_t CWalletTx::GetChange() const
@@ -2080,7 +2174,7 @@ bool CWallet::CreateTransaction(const vector<pair<CScript, int64_t> >& vecSend,
                     wtxNew.vin.push_back(CTxIn(coin.first->GetHash(),coin.second));
 
                 // Sign
-                int nIn = 0;
+                uint32_t nIn = 0;
                 for(const auto& coin : setCoins)
                     if (!SignSignature(*this, *coin.first, wtxNew, nIn++))
                         return false;
@@ -2240,7 +2334,7 @@ bool CWallet::MergeCoins(const int64_t& nAmount, const int64_t& nMinValue, const
         if (wtxNew.vout[0].nValue <= 0)
             return false;
 
-        for (unsigned int i = 0; i < wtxNew.vin.size(); i++) {
+        for (uint32_t i = 0; i < wtxNew.vin.size(); i++) {
             const CWalletTx *txin = vwtxPrev[i];
 
             // Sign all scripts again
@@ -2417,7 +2511,7 @@ bool CWallet::CreateCoinStake(uint256 &hashTx, uint32_t nOut, uint32_t nGenerati
         }
 
         // Sign
-        int nIn = 0;
+        uint32_t nIn = 0;
         for(const CWalletTx* pcoin :  vwtxPrev)
         {
             if (!SignSignature(*this, *pcoin, txNew, nIn++))
@@ -2425,7 +2519,7 @@ bool CWallet::CreateCoinStake(uint256 &hashTx, uint32_t nOut, uint32_t nGenerati
         }
 
         // Limit size
-        unsigned int nBytes = ::GetSerializeSize(txNew, SER_NETWORK, PROTOCOL_VERSION);
+        auto nBytes = ::GetSerializeSize(txNew, SER_NETWORK, PROTOCOL_VERSION);
         if (nBytes >= MAX_BLOCK_SIZE_GEN/5)
             return error("CreateCoinStake : exceeded coinstake size limit\n");
 
@@ -2506,22 +2600,22 @@ string CWallet::SendMoney(CScript scriptPubKey, int64_t nValue, CWalletTx& wtxNe
 {
     // Check amount
     if (nValue <= 0)
-        return _("Invalid amount");
+        return "Invalid amount";
     if (nValue + nTransactionFee > GetBalance())
-        return _("Insufficient funds");
+        return "Insufficient funds";
 
     CReserveKey reservekey(this);
     int64_t nFeeRequired;
 
     if (IsLocked())
     {
-        string strError = _("Error: Wallet locked, unable to create transaction  ");
+        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.");
+        string strError("Error: Wallet unlocked for block minting only, unable to create transaction.");
         printf("SendMoney() : %s", strError.c_str());
         return strError;
     }
@@ -2540,7 +2634,7 @@ string CWallet::SendMoney(CScript scriptPubKey, int64_t nValue, CWalletTx& wtxNe
         return "ABORTED";
 
     if (!CommitTransaction(wtxNew, reservekey))
-        return _("Error: The transaction was rejected.  This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here.");
+        return "Error: The transaction was rejected.  This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here.";
 
     return "";
 }
@@ -2636,6 +2730,16 @@ 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++;
+    }
+}
+
 bool CWallet::GetTransaction(const uint256 &hashTx, CWalletTx& wtx)
 {
     {
@@ -2883,29 +2987,38 @@ set< set<CBitcoinAddress> > CWallet::GetAddressGroupings()
     {
         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
             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
+            if (any_mine)
+            {
             for(CTxOut txout :  pcoin->vout)
                 if (IsChange(txout))
                 {
-                    auto 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