PPCoin: fix a hang during reorg (bug introduced in coinstake)
authorSunny King <p2pcoin@gmail.com>
Thu, 16 Feb 2012 03:47:39 +0000 (03:47 +0000)
committerSunny King <p2pcoin@gmail.com>
Thu, 16 Feb 2012 03:47:39 +0000 (03:47 +0000)
        fix a condition for coinstake in ReacceptWalletTransaction
        some minor cleanups

src/bitcoinrpc.cpp
src/main.cpp
src/main.h
src/wallet.cpp

index 22d4b89..18dccf5 100644 (file)
@@ -1644,7 +1644,7 @@ Value getwork(const Array& params, bool fHelp)
             nStart = GetTime();
 
             // Create new block
-            pblock = CreateNewBlock(reservekey, pwalletMain);
+            pblock = CreateNewBlock(pwalletMain);
             if (!pblock)
                 throw JSONRPCError(-7, "Out of memory");
             vNewBlock.push_back(pblock);
@@ -1742,7 +1742,7 @@ Value getmemorypool(const Array& params, bool fHelp)
             // Create new block
             if(pblock)
                 delete pblock;
-            pblock = CreateNewBlock(reservekey, pwalletMain);
+            pblock = CreateNewBlock(pwalletMain);
             if (!pblock)
                 throw JSONRPCError(-7, "Out of memory");
         }
index 71bc1ce..7cd7414 100644 (file)
@@ -933,8 +933,8 @@ bool CTransaction::ConnectInputs(CTxDB& txdb, map<uint256, CTxIndex>& mapTestPoo
         if (IsCoinStake())
         {
             // ppcoin: coin stake tx earns reward instead of paying fee
-            uint64 nCoinAge = 0;
-            if (!GetCoinAge(nCoinAge))
+            uint64 nCoinAge;
+            if (!GetCoinAge(txdb, nCoinAge))
                 return error("ConnectInputs() : %s unable to get coin age for coinstake", GetHash().ToString().substr(0,10).c_str());
             int64 nStakeReward = GetValueOut() - nValueIn;
             if (nStakeReward > GetProofOfStakeReward(nCoinAge))
@@ -1257,7 +1257,7 @@ bool CBlock::SetBestChain(CTxDB& txdb, CBlockIndex* pindexNew)
 // guaranteed to be in main chain by auto checkpoint. This rule is
 // introduced to help nodes establish a consistent view of the coin
 // age (trust score) of competing branches.
-bool CTransaction::GetCoinAge(uint64& nCoinAge) const
+bool CTransaction::GetCoinAge(CTxDB& txdb, uint64& nCoinAge) const
 {
     CBigNum bnCentSecond = 0;  // coin age in the unit of cent-seconds
     nCoinAge = 0;
@@ -1268,7 +1268,6 @@ bool CTransaction::GetCoinAge(uint64& nCoinAge) const
     BOOST_FOREACH(const CTxIn& txin, vin)
     {
         // First try finding the previous transaction in database
-        CTxDB txdb("r");
         CTransaction txPrev;
         CTxIndex txindex;
         if (!txPrev.ReadFromDisk(txdb, txin.prevout, txindex))
@@ -1290,23 +1289,23 @@ bool CTransaction::GetCoinAge(uint64& nCoinAge) const
             printf("coin age nValueIn=%-12I64d nTimeDiff=%d bnCentSecond=%s\n", nValueIn, nTime - txPrev.nTime, bnCentSecond.ToString().c_str());
     }
 
-    CBigNum bnCoinAge = bnCentSecond * CENT / COIN / (24 * 60 * 60);
+    CBigNum bnCoinDay = bnCentSecond * CENT / COIN / (24 * 60 * 60);
     if (fDebug && GetBoolArg("-printcoinage"))
-        printf("coin age nCoinDays=%s\n", bnCoinAge.ToString().c_str());
-    nCoinAge = bnCoinAge.getuint64();
+        printf("coin age bnCoinDay=%s\n", bnCoinDay.ToString().c_str());
+    nCoinAge = bnCoinDay.getuint64();
     return true;
 }
 
 // ppcoin: total coin age spent in block, in the unit of coin-days.
 bool CBlock::GetCoinAge(uint64& nCoinAge) const
 {
-    CBigNum bnCentSecond = 0;
     nCoinAge = 0;
 
+    CTxDB txdb("r");
     BOOST_FOREACH(const CTransaction& tx, vtx)
     {
-        uint64 nTxCoinAge = 0;
-        if (tx.GetCoinAge(nTxCoinAge))
+        uint64 nTxCoinAge;
+        if (tx.GetCoinAge(txdb, nTxCoinAge))
             nCoinAge += nTxCoinAge;
         else
             return false;
@@ -1346,7 +1345,7 @@ bool CBlock::AddToBlockIndex(unsigned int nFile, unsigned int nBlockPos)
     }
 
     // ppcoin: compute chain trust score
-    uint64 nCoinAge = 0;
+    uint64 nCoinAge;
     if (!GetCoinAge(nCoinAge))
         return error("AddToBlockIndex() : invalid transaction in block");
     pindexNew->nChainTrust = (pindexNew->pprev ? pindexNew->pprev->nChainTrust : 0) + nCoinAge;
@@ -2864,9 +2863,10 @@ public:
 };
 
 
-CBlock* CreateNewBlock(CReserveKey& reservekey, CWallet* pwallet)
+CBlock* CreateNewBlock(CWallet* pwallet)
 {
     CBlockIndex* pindexPrev = pindexBest;
+    CReserveKey reservekey(pwallet);
 
     // Create new block
     auto_ptr<CBlock> pblock(new CBlock());
@@ -2887,8 +2887,6 @@ CBlock* CreateNewBlock(CReserveKey& reservekey, CWallet* pwallet)
     CTransaction txCoinStake;
     if (pwallet->CreateCoinStake(txNew.vout[0].scriptPubKey, txCoinStake))
         pblock->vtx.push_back(txCoinStake);
-    else
-        printf("CreateNewBlock: unable to find coins to stake\n");
 
     // Collect memory pool transactions into the block
     int64 nFees = 0;
@@ -3154,7 +3152,7 @@ void static BitcoinMiner(CWallet *pwallet)
         unsigned int nTransactionsUpdatedLast = nTransactionsUpdated;
         CBlockIndex* pindexPrev = pindexBest;
 
-        auto_ptr<CBlock> pblock(CreateNewBlock(reservekey, pwallet));
+        auto_ptr<CBlock> pblock(CreateNewBlock(pwallet));
         if (!pblock.get())
             return;
         IncrementExtraNonce(pblock.get(), pindexPrev, nExtraNonce);
index 35580d4..2203598 100644 (file)
@@ -95,7 +95,7 @@ void PrintBlockTree();
 bool ProcessMessages(CNode* pfrom);
 bool SendMessages(CNode* pto, bool fSendTrickle);
 void GenerateBitcoins(bool fGenerate, CWallet* pwallet);
-CBlock* CreateNewBlock(CReserveKey& reservekey, CWallet* pwallet);
+CBlock* CreateNewBlock(CWallet* pwallet);
 void IncrementExtraNonce(CBlock* pblock, CBlockIndex* pindexPrev, unsigned int& nExtraNonce);
 void FormatHashBuffers(CBlock* pblock, char* pmidstate, char* pdata, char* phash1);
 bool CheckWork(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey);
@@ -665,7 +665,7 @@ protected:
     bool AddToMemoryPoolUnchecked();
 public:
     bool RemoveFromMemoryPool();
-    bool GetCoinAge(uint64& nCoinAge) const;  // ppcoin: get transaction coin age
+    bool GetCoinAge(CTxDB& txdb, uint64& nCoinAge) const;  // ppcoin: get transaction coin age
 };
 
 
index 085d23c..8405d16 100644 (file)
@@ -598,7 +598,7 @@ void CWallet::ReacceptWalletTransactions()
         BOOST_FOREACH(PAIRTYPE(const uint256, CWalletTx)& item, mapWallet)
         {
             CWalletTx& wtx = item.second;
-            if ((wtx.IsCoinBase() || wtx.IsCoinStake()) && wtx.IsSpent(0))
+            if ((wtx.IsCoinBase() && wtx.IsSpent(0)) || (wtx.IsCoinStake() && wtx.IsSpent(1)))
                 continue;
 
             CTxIndex txindex;
@@ -1062,52 +1062,51 @@ bool CWallet::CreateCoinStake(CScript scriptPubKey, CTransaction& txNew)
     CRITICAL_BLOCK(cs_main)
     CRITICAL_BLOCK(cs_wallet)
     {
-        // txdb must be opened before the mapWallet lock
-        CTxDB txdb("r");
+        txNew.vin.clear();
+        txNew.vout.clear();
+        // Mark coin stake transaction
+        CScript scriptEmpty;
+        scriptEmpty.clear();
+        txNew.vout.push_back(CTxOut(0, scriptEmpty));
+        // Choose coins to use
+        set<pair<const CWalletTx*,unsigned int> > setCoins;
+        int64 nValueIn = 0;
+        if (!SelectCoins(GetBalance(), txNew.nTime, setCoins, nValueIn))
+            return false;
+        int64 nCredit = 0;
+        BOOST_FOREACH(PAIRTYPE(const CWalletTx*, unsigned int) pcoin, setCoins)
+        {
+            nCredit += pcoin.first->vout[pcoin.second].nValue;
+            // Only spend one tx for now
+            break;
+        }
+        // Fill vin
+        BOOST_FOREACH(const PAIRTYPE(const CWalletTx*,unsigned int)& coin, setCoins)
+        {
+            txNew.vin.push_back(CTxIn(coin.first->GetHash(),coin.second));
+            // Only spend one tx for now
+            break;
+        }
+        // Calculate coin age reward
         {
-            txNew.vin.clear();
-            txNew.vout.clear();
-            // Mark coin stake transaction
-            CScript scriptEmpty;
-            scriptEmpty.clear();
-            txNew.vout.push_back(CTxOut(0, scriptEmpty));
-            // Choose coins to use
-            set<pair<const CWalletTx*,unsigned int> > setCoins;
-            int64 nValueIn = 0;
-            if (!SelectCoins(GetBalance(), txNew.nTime, setCoins, nValueIn))
-                return false;
-            int64 nCredit = 0;
-            BOOST_FOREACH(PAIRTYPE(const CWalletTx*, unsigned int) pcoin, setCoins)
-            {
-                nCredit += pcoin.first->vout[pcoin.second].nValue;
-                // Only spend one tx for now
-                break;
-            }
-            // Fill vin
-            BOOST_FOREACH(const PAIRTYPE(const CWalletTx*,unsigned int)& coin, setCoins)
-            {
-                txNew.vin.push_back(CTxIn(coin.first->GetHash(),coin.second));
-                // Only spend one tx for now
-                break;
-            }
-            // Calculate coin age reward
             uint64 nCoinAge;
-            if (!txNew.GetCoinAge(nCoinAge))
+            CTxDB txdb("r");
+            if (!txNew.GetCoinAge(txdb, nCoinAge))
                 return false;
             nCredit += GetProofOfStakeReward(nCoinAge);
-            // Fill vout
-            txNew.vout.push_back(CTxOut(nCredit, scriptPubKey));
+        }
+        // Fill vout
+        txNew.vout.push_back(CTxOut(nCredit, scriptPubKey));
 
 
-            // Sign
-            int nIn = 0;
-            BOOST_FOREACH(const PAIRTYPE(const CWalletTx*,unsigned int)& coin, setCoins)
-            {
-                if (!SignSignature(*this, *coin.first, txNew, nIn++))
-                    return false;
-                // Only spend one tx for now
-                break;
-            }
+        // Sign
+        int nIn = 0;
+        BOOST_FOREACH(const PAIRTYPE(const CWalletTx*,unsigned int)& coin, setCoins)
+        {
+            if (!SignSignature(*this, *coin.first, txNew, nIn++))
+                return false;
+            // Only spend one tx for now
+            break;
         }
     }
     return true;