PPCoin: Add RPC command 'repairwallet'
authorSunny King <sunnyking9999@gmail.com>
Thu, 22 Mar 2012 18:02:37 +0000 (18:02 +0000)
committerSunny King <sunnyking9999@gmail.com>
Thu, 22 Mar 2012 18:02:37 +0000 (18:02 +0000)
src/bitcoinrpc.cpp
src/wallet.cpp
src/wallet.h

index e9b9dfb..ecd35ac 100644 (file)
@@ -1906,6 +1906,31 @@ Value checkwallet(const Array& params, bool fHelp)
 }
 
 
+// ppcoin: repair wallet
+Value repairwallet(const Array& params, bool fHelp)
+{
+    if (fHelp || params.size() > 0)
+        throw runtime_error(
+            "repairwallet\n"
+            "Repair wallet if checkwallet reports any problem.\n");
+
+    int nMismatchSpent;
+    int64 nBalanceInQuestion;
+    pwalletMain->FixSpentCoins(nMismatchSpent, nBalanceInQuestion);
+    Object result;
+    if (nMismatchSpent == 0)
+    {
+        result.push_back(Pair("wallet check passed", true));
+    }
+    else
+    {
+        result.push_back(Pair("mismatched spent coins", nMismatchSpent));
+        result.push_back(Pair("amount affected by repair", ValueFromAmount(nBalanceInQuestion)));
+    }
+    return result;
+}
+
+
 
 
 
@@ -1960,6 +1985,7 @@ pair<string, rpcfn_type> pCallTable[] =
     make_pair("getbranchpoint",         &getbranchpoint),
     make_pair("reservebalance",         &reservebalance),
     make_pair("checkwallet",            &checkwallet),
+    make_pair("repairwallet",           &repairwallet),
 };
 map<string, rpcfn_type> mapCallTable(pCallTable, pCallTable + sizeof(pCallTable)/sizeof(pCallTable[0]));
 
index e469803..29cc87a 100644 (file)
@@ -1510,6 +1510,48 @@ bool CWallet::CheckSpentCoins(int& nMismatchFound, int64& nBalanceInQuestion)
     return (nMismatchFound == 0);
 }
 
+// ppcoin: fix wallet spent state according to txindex
+void CWallet::FixSpentCoins(int& nMismatchFound, int64& nBalanceInQuestion)
+{
+    nMismatchFound = 0;
+    nBalanceInQuestion = 0;
+    CRITICAL_BLOCK(cs_wallet)
+    {
+       vector<CWalletTx*> vCoins;
+       vCoins.reserve(mapWallet.size());
+       for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
+           vCoins.push_back(&(*it).second);
+
+       CTxDB txdb("r");
+       BOOST_FOREACH(CWalletTx* pcoin, vCoins)
+       {
+           // Find the corresponding transaction index
+           CTxIndex txindex;
+           if (!txdb.ReadTxIndex(pcoin->GetHash(), txindex))
+               continue;
+           for (int n=0; n < pcoin->vout.size(); n++)
+           {
+               if (pcoin->IsSpent(n) && (txindex.vSpent.size() <= n || txindex.vSpent[n].IsNull()))
+               {
+                   printf("FixSpentCoins found lost coin %sppc %s[%d]\n", FormatMoney(pcoin->GetCredit()).c_str(), pcoin->GetHash().ToString().c_str(), n);
+                   nMismatchFound++;
+                   nBalanceInQuestion += pcoin->vout[n].nValue;
+                   pcoin->MarkUnspent(n);
+                   pcoin->WriteToDisk();
+               }
+               else if (!pcoin->IsSpent(n) && (txindex.vSpent.size() > n && !txindex.vSpent[n].IsNull()))
+               {
+                   printf("FixSpentCoins found spent coin %sppc %s[%d]\n", FormatMoney(pcoin->GetCredit()).c_str(), pcoin->GetHash().ToString().c_str(), n);
+                   nMismatchFound++;
+                   nBalanceInQuestion += pcoin->vout[n].nValue;
+                   pcoin->MarkSpent(n);
+                   pcoin->WriteToDisk();
+               }
+           }
+       }
+    }
+}
+
 vector<unsigned char> CReserveKey::GetReservedKey()
 {
     if (nIndex == -1)
index 970f2e4..2fb41db 100644 (file)
@@ -215,6 +215,7 @@ public:
     bool SetDefaultKey(const std::vector<unsigned char> &vchPubKey);
 
     bool CheckSpentCoins(int& nMismatchSpent, int64& nBalanceInQuestion);
+    void FixSpentCoins(int& nMismatchSpent, int64& nBalanceInQuestion);
 };
 
 
@@ -408,6 +409,18 @@ public:
         }
     }
 
+    void 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 = false;
+        }
+    }
+
     bool IsSpent(unsigned int nOut) const
     {
         if (nOut >= vout.size())