From b3a022069bb4209f07eff94e1b1e075c1182bc79 Mon Sep 17 00:00:00 2001 From: Sunny King Date: Thu, 16 Feb 2012 03:47:39 +0000 Subject: [PATCH] PPCoin: fix a hang during reorg (bug introduced in coinstake) fix a condition for coinstake in ReacceptWalletTransaction some minor cleanups --- src/bitcoinrpc.cpp | 4 +- src/main.cpp | 28 ++++++++--------- src/main.h | 4 +- src/wallet.cpp | 81 +++++++++++++++++++++++++-------------------------- 4 files changed, 57 insertions(+), 60 deletions(-) diff --git a/src/bitcoinrpc.cpp b/src/bitcoinrpc.cpp index 22d4b89..18dccf5 100644 --- a/src/bitcoinrpc.cpp +++ b/src/bitcoinrpc.cpp @@ -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"); } diff --git a/src/main.cpp b/src/main.cpp index 71bc1ce..7cd7414 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -933,8 +933,8 @@ bool CTransaction::ConnectInputs(CTxDB& txdb, map& 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 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 pblock(CreateNewBlock(reservekey, pwallet)); + auto_ptr pblock(CreateNewBlock(pwallet)); if (!pblock.get()) return; IncrementExtraNonce(pblock.get(), pindexPrev, nExtraNonce); diff --git a/src/main.h b/src/main.h index 35580d4..2203598 100644 --- a/src/main.h +++ b/src/main.h @@ -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 }; diff --git a/src/wallet.cpp b/src/wallet.cpp index 085d23c..8405d16 100644 --- a/src/wallet.cpp +++ b/src/wallet.cpp @@ -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 > 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 > 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; -- 1.7.1