Batch block connection during initial block download
authoralex <alex@alex-VirtualBox.(none)>
Sat, 18 Jan 2014 23:34:13 +0000 (03:34 +0400)
committeralex <alex@alex-VirtualBox.(none)>
Sat, 18 Jan 2014 23:34:13 +0000 (03:34 +0400)
This reduces the load on the database engine, as subsequent blocks often
update an earlier block's transaction already.

12 files changed:
src/db.cpp
src/db.h
src/init.cpp
src/kernel.cpp
src/main.cpp
src/main.h
src/miner.cpp
src/qt/transactiondesc.cpp
src/rpcmining.cpp
src/rpcrawtransaction.cpp
src/wallet.cpp
src/wallet.h

index 13127ba..9fbcc8a 100644 (file)
@@ -4,10 +4,10 @@
 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
 
 #include "db.h"
-#include "kernel.h"
-#include "checkpoints.h"
 #include "util.h"
 #include "main.h"
+#include "kernel.h"
+#include "checkpoints.h"
 #include <boost/version.hpp>
 #include <boost/filesystem.hpp>
 #include <boost/filesystem/fstream.hpp>
@@ -81,8 +81,8 @@ bool CDBEnv::Open(boost::filesystem::path pathEnv_)
     dbenv.set_cachesize(nDbCache / 1024, (nDbCache % 1024)*1048576, 1);
     dbenv.set_lg_bsize(1048576);
     dbenv.set_lg_max(10485760);
-    dbenv.set_lk_max_locks(10000);
-    dbenv.set_lk_max_objects(10000);
+    dbenv.set_lk_max_locks(40000);
+    dbenv.set_lk_max_objects(40000);
     dbenv.set_errfile(fopen(pathErrorFile.string().c_str(), "a")); /// debug
     dbenv.set_flags(DB_AUTO_COMMIT, 1);
     dbenv.set_flags(DB_TXN_WRITE_NOSYNC, 1);
@@ -285,14 +285,10 @@ static bool IsChainFile(std::string strFile)
     return false;
 }
 
-void CDB::Close()
+void CDB::Flush()
 {
-    if (!pdb)
-        return;
     if (activeTxn)
-        activeTxn->abort();
-    activeTxn = NULL;
-    pdb = NULL;
+        return;
 
     // Flush database activity from memory pool to disk log
     unsigned int nMinutes = 0;
@@ -304,6 +300,18 @@ void CDB::Close()
         nMinutes = 5;
 
     bitdb.dbenv.txn_checkpoint(nMinutes ? GetArg("-dblogsize", 100)*1024 : 0, nMinutes, 0);
+}
+
+void CDB::Close()
+{
+    if (!pdb)
+        return;
+    if (activeTxn)
+        activeTxn->abort();
+    activeTxn = NULL;
+    pdb = NULL;
+
+    Flush();
 
     {
         LOCK(bitdb.cs_db);
@@ -531,18 +539,6 @@ bool CChainDB::WriteBlockFileInfo(int nFile, const CBlockFileInfo &info) {
     return Write(make_pair('f', nFile), info);
 }
 
-bool CChainDB::ReadBlockFileInfo(int nFile, CBlockFileInfo &info) {
-    return Read(make_pair('f', nFile), info);
-}
-
-bool CChainDB::WriteLastBlockFile(int nFile) {
-    return Write('l', nFile);
-}
-
-bool CChainDB::ReadLastBlockFile(int &nFile) {
-    return Read('l', nFile);
-}
-
 bool CChainDB::ReadSyncCheckpoint(uint256& hashCheckpoint)
 {
     return Read('H', hashCheckpoint);
@@ -563,6 +559,55 @@ bool CChainDB::WriteCheckpointPubKey(const string& strPubKey)
     return Write('K', strPubKey);
 }
 
+
+bool CChainDB::ReadBlockFileInfo(int nFile, CBlockFileInfo &info) {
+    return Read(make_pair('f', nFile), info);
+}
+
+bool CChainDB::WriteLastBlockFile(int nFile) {
+    return Write('l', nFile);
+}
+
+bool CChainDB::ReadLastBlockFile(int &nFile) {
+    return Read('l', nFile);
+}
+
+CCoinsViewDB::CCoinsViewDB() : db("cr+") {}
+bool CCoinsViewDB::GetCoins(uint256 txid, CCoins &coins) { return db.ReadCoins(txid, coins); }
+bool CCoinsViewDB::SetCoins(uint256 txid, const CCoins &coins) { return db.WriteCoins(txid, coins); }
+bool CCoinsViewDB::HaveCoins(uint256 txid) { return db.HaveCoins(txid); }
+CBlockIndex *CCoinsViewDB::GetBestBlock() {
+    uint256 hashBestChain;
+    if (!db.ReadHashBestChain(hashBestChain))
+        return NULL;
+    std::map<uint256, CBlockIndex*>::iterator it = mapBlockIndex.find(hashBestChain);
+    if (it == mapBlockIndex.end())
+        return NULL;
+    return it->second;
+}
+bool CCoinsViewDB::SetBestBlock(CBlockIndex *pindex) { return db.WriteHashBestChain(pindex->GetBlockHash()); }
+bool CCoinsViewDB::BatchWrite(const std::map<uint256, CCoins> &mapCoins, CBlockIndex *pindex) {
+    printf("Committing %u changed transactions to coin database...\n", (unsigned int)mapCoins.size());
+
+    if (!db.TxnBegin())
+        return false;
+    bool fOk = true;
+    for (std::map<uint256, CCoins>::const_iterator it = mapCoins.begin(); it != mapCoins.end(); it++) {
+        fOk = db.WriteCoins(it->first, it->second);
+        if (!fOk)
+            break;
+    }
+    if (fOk)
+        fOk = db.WriteHashBestChain(pindex->GetBlockHash());
+
+    if (!fOk)
+        db.TxnAbort();
+    else
+        fOk = db.TxnCommit();
+
+    return fOk;
+}
+
 CBlockIndex static * InsertBlockIndex(uint256 hash)
 {
     if (hash == 0)
@@ -583,7 +628,7 @@ CBlockIndex static * InsertBlockIndex(uint256 hash)
     return pindexNew;
 }
 
-bool LoadBlockIndex(CCoinsDB &coindb, CChainDB &chaindb)
+bool LoadBlockIndex(CChainDB &chaindb)
 {
     if (!chaindb.LoadBlockIndexGuts())
         return false;
@@ -604,7 +649,8 @@ bool LoadBlockIndex(CCoinsDB &coindb, CChainDB &chaindb)
     {
         CBlockIndex* pindex = item.second;
         pindex->nChainTrust = (pindex->pprev ? pindex->pprev->nChainTrust : 0) + pindex->GetBlockTrust();
-        // NovaCoin: calculate stake modifier checksum
+
+        // Calculate stake modifier checksum
         pindex->nStakeModifierChecksum = GetStakeModifierChecksum(pindex);
         if (!CheckStakeModifierCheckpoints(pindex->nHeight, pindex->nStakeModifierChecksum))
             return error("CTxDB::LoadBlockIndex() : Failed stake modifier checkpoint height=%d, modifier=0x%016"PRI64x, pindex->nHeight, pindex->nStakeModifier);
@@ -617,26 +663,23 @@ bool LoadBlockIndex(CCoinsDB &coindb, CChainDB &chaindb)
         printf("LoadBlockIndex(): last block file: %s\n", infoLastBlockFile.ToString().c_str());
  
     // Load hashBestChain pointer to end of best chain
-    if (!coindb.ReadHashBestChain(hashBestChain))
+    pindexBest = pcoinsTip->GetBestBlock();
+    if (pindexBest == NULL)
     {
         if (pindexGenesisBlock == NULL)
             return true;
         return error("CTxDB::LoadBlockIndex() : hashBestChain not loaded");
     }
-    std::map<uint256, CBlockIndex*>::iterator it = mapBlockIndex.find(hashBestChain);
-    if (it == mapBlockIndex.end()) {
-        return error("CTxDB::LoadBlockIndex() : hashBestChain not found in the block index");
-    } else {
-        // set 'next' pointers in best chain
-        CBlockIndex *pindex = it->second;
-        while(pindex != NULL && pindex->pprev != NULL) {
-             CBlockIndex *pindexPrev = pindex->pprev;
-             pindexPrev->pnext = pindex;
-             pindex = pindexPrev;
-        }
-        pindexBest = it->second;
-        nBestHeight = pindexBest->nHeight;
-        nBestChainTrust = pindexBest->nChainTrust;
+    hashBestChain = pindexBest->GetBlockHash();
+    nBestHeight = pindexBest->nHeight;
+    nBestChainTrust = pindexBest->nChainTrust;
+
+    // set 'next' pointers in best chain
+    CBlockIndex *pindex = pindexBest;
+    while(pindex != NULL && pindex->pprev != NULL) {
+         CBlockIndex *pindexPrev = pindex->pprev;
+         pindexPrev->pnext = pindex;
+         pindex = pindexPrev;
     }
     printf("LoadBlockIndex(): hashBestChain=%s  height=%d date=%s\n",
         hashBestChain.ToString().substr(0,20).c_str(), nBestHeight,
@@ -829,8 +872,6 @@ bool CAddrDB::Read(CAddrMan& addr)
     // use file size to size memory buffer
     int fileSize = GetFilesize(filein);
     int dataSize = fileSize - sizeof(uint256);
-    //Don't try to resize to a negative number if file is small
-    if ( dataSize < 0 ) dataSize = 0;
     vector<unsigned char> vchData;
     vchData.resize(dataSize);
     uint256 hashIn;
index 1ac971d..bc6a5a5 100644 (file)
--- a/src/db.h
+++ b/src/db.h
@@ -102,6 +102,7 @@ protected:
     explicit CDB(const char* pszFile, const char* pszMode="r+");
     ~CDB() { Close(); }
 public:
+    void Flush();
     void Close();
 private:
     CDB(const CDB&);
@@ -330,6 +331,23 @@ public:
     bool WriteHashBestChain(uint256 hashBestChain);
 };
 
+
+/** CCoinsView backed by a CCoinsDB */
+class CCoinsViewDB : public CCoinsView
+{
+protected:
+    CCoinsDB db;
+public:
+    CCoinsViewDB();
+    bool GetCoins(uint256 txid, CCoins &coins);
+    bool SetCoins(uint256 txid, const CCoins &coins);
+    bool HaveCoins(uint256 txid);
+    CBlockIndex *GetBestBlock();
+    bool SetBestBlock(CBlockIndex *pindex);
+    bool BatchWrite(const std::map<uint256, CCoins> &mapCoins, CBlockIndex *pindex);
+};
+
+
 /** Access to the block database (chain.dat) */
 class CChainDB : public CDB
 {
@@ -354,7 +372,7 @@ public:
 };
 
 
-bool LoadBlockIndex(CCoinsDB &coinsdb, CChainDB &chaindb);
+bool LoadBlockIndex(CChainDB &chaindb);
 
 
 /** Access to the (IP) address database (peers.dat) */
index 39fba49..ef0067f 100644 (file)
@@ -60,6 +60,8 @@ void StartShutdown()
 #endif
 }
 
+static CCoinsViewDB *pcoinsdbview;
+
 void Shutdown(void* parg)
 {
     static CCriticalSection cs_Shutdown;
@@ -84,6 +86,12 @@ void Shutdown(void* parg)
         nTransactionsUpdated++;
         bitdb.Flush(false);
         StopNode();
+        {
+            LOCK(cs_main);
+            pcoinsTip->Flush();
+            delete pcoinsTip;
+            delete pcoinsdbview;
+        }
         bitdb.Flush(true);
         boost::filesystem::remove(GetPidFile());
         UnregisterWallet(pwalletMain);
@@ -698,10 +706,12 @@ bool AppInit2()
     uiInterface.InitMessage(_("Loading block index..."));
     printf("Loading block index...\n");
     nStart = GetTimeMillis();
+    pcoinsdbview = new CCoinsViewDB();
+    pcoinsTip = new CCoinsViewCache(*pcoinsdbview);
+
     if (!LoadBlockIndex())
         return InitError(_("Error loading blkindex.dat"));
 
-
     // as LoadBlockIndex can take several minutes, it's possible the user
     // requested to kill bitcoin-qt during the last operation. If so, exit.
     // As the program has not fully started yet, Shutdown() is possibly overkill.
index dabb053..6ff8e60 100644 (file)
@@ -345,8 +345,7 @@ bool CheckProofOfStake(const CTransaction& tx, unsigned int nBits, uint256& hash
 
     CTransaction txPrev;
     CCoins coins;
-    CCoinsDB coindb("r");
-    CCoinsViewDB view(coindb);
+    CCoinsViewCache &view = *pcoinsTip;
 
     if (!view.GetCoins(txin.prevout.hash, coins))
         return tx.DoS(1, error("CheckProofOfStake() : INFO: read coins for txPrev failed"));  // previous transaction not in main chain, may occur during initial download
index 437db1a..a65b31f 100644 (file)
@@ -194,6 +194,7 @@ bool CCoinsView::SetCoins(uint256 txid, const CCoins &coins) { return false; }
 bool CCoinsView::HaveCoins(uint256 txid) { return false; }
 CBlockIndex *CCoinsView::GetBestBlock() { return NULL; }
 bool CCoinsView::SetBestBlock(CBlockIndex *pindex) { return false; }
+bool CCoinsView::BatchWrite(const std::map<uint256, CCoins> &mapCoins, CBlockIndex *pindex) { return false; }
 
 CCoinsViewBacked::CCoinsViewBacked(CCoinsView &viewIn) : base(&viewIn) { }
 bool CCoinsViewBacked::GetCoins(uint256 txid, CCoins &coins) { return base->GetCoins(txid, coins); }
@@ -203,12 +204,7 @@ CBlockIndex *CCoinsViewBacked::GetBestBlock() { return base->GetBestBlock(); }
 bool CCoinsViewBacked::SetBestBlock(CBlockIndex *pindex) { return base->SetBestBlock(pindex); }
 void CCoinsViewBacked::SetBackend(CCoinsView &viewIn) { base = &viewIn; }
 
-CCoinsViewDB::CCoinsViewDB(CCoinsDB &dbIn) : db(dbIn) {}
-bool CCoinsViewDB::GetCoins(uint256 txid, CCoins &coins) { return db.ReadCoins(txid, coins); }
-bool CCoinsViewDB::SetCoins(uint256 txid, const CCoins &coins) { return db.WriteCoins(txid, coins); }
-bool CCoinsViewDB::HaveCoins(uint256 txid) { return db.HaveCoins(txid); }
-CBlockIndex *CCoinsViewDB::GetBestBlock() { return pindexBest; }
-bool CCoinsViewDB::SetBestBlock(CBlockIndex *pindex) { return db.WriteHashBestChain(pindex->GetBlockHash()); }
+bool CCoinsViewBacked::BatchWrite(const std::map<uint256, CCoins> &mapCoins, CBlockIndex *pindex) { return base->BatchWrite(mapCoins, pindex); }
 
 CCoinsViewCache::CCoinsViewCache(CCoinsView &baseIn, bool fDummy) : CCoinsViewBacked(baseIn), pindexTip(NULL) { }
 
@@ -244,18 +240,24 @@ bool CCoinsViewCache::SetBestBlock(CBlockIndex *pindex) {
     return true;
 }
 
-bool CCoinsViewCache::Flush() {
-    for (std::map<uint256,CCoins>::iterator it = cacheCoins.begin(); it != cacheCoins.end(); it++) {
-        if (!base->SetCoins(it->first, it->second))
-            return false;
-    }
-    if (!base->SetBestBlock(pindexTip))
-        return false;
-    cacheCoins.clear();
-    pindexTip = NULL;
+bool CCoinsViewCache::BatchWrite(const std::map<uint256, CCoins> &mapCoins, CBlockIndex *pindex) {
+    for (std::map<uint256, CCoins>::const_iterator it = mapCoins.begin(); it != mapCoins.end(); it++)
+        cacheCoins[it->first] = it->second;
+    pindexTip = pindex;
     return true;
 }
 
+bool CCoinsViewCache::Flush() {
+    bool fOk = base->BatchWrite(cacheCoins, pindexTip);
+    if (fOk)
+        cacheCoins.clear();
+    return fOk;
+}
+
+unsigned int CCoinsViewCache::GetCacheSize() {
+    return cacheCoins.size();
+}
+
 /** CCoinsView that brings transactions from a memorypool into view.
     It does not check for spendings by memory pool transactions. */
 CCoinsViewMemPool::CCoinsViewMemPool(CCoinsView &baseIn, CTxMemPool &mempoolIn) : CCoinsViewBacked(baseIn), mempool(mempoolIn) { }
@@ -275,6 +277,7 @@ bool CCoinsViewMemPool::HaveCoins(uint256 txid) {
     return mempool.exists(txid) || base->HaveCoins(txid);
 }
 
+CCoinsViewCache *pcoinsTip = NULL;
 
 //////////////////////////////////////////////////////////////////////////////
 //
@@ -468,11 +471,9 @@ int CMerkleTx::SetMerkleBranch(const CBlock* pblock)
     else
     {
         CBlock blockTmp;
-
         if (pblock == NULL) {
-            CCoinsDB coinsdb("r");
             CCoins coins;
-            if (coinsdb.ReadCoins(GetHash(), coins)) {
+            if (pcoinsTip->GetCoins(GetHash(), coins)) {
                 CBlockIndex *pindex = FindBlockByHeight(coins.nHeight);
                 if (pindex) {
                     if (!blockTmp.ReadFromDisk(pindex))
@@ -533,7 +534,7 @@ bool CTransaction::CheckTransaction() const
         if (txout.IsEmpty() && !IsCoinBase() && !IsCoinStake())
             return DoS(100, error("CTransaction::CheckTransaction() : txout empty for user transaction"));
 
-        // NovaCoin: enforce minimum output amount for user transactions until 1 May 2014 04:00:00 GMT
+        // Enforce minimum output amount for user transactions until 1 May 2014 04:00:00 GMT
         if (!fTestNet && !IsCoinBase() && !txout.IsEmpty() && nTime < OUTPUT_SWITCH_TIME && txout.nValue < MIN_TXOUT_AMOUNT)
             return DoS(100, error("CTransaction::CheckTransaction() : txout.nValue below minimum"));
 
@@ -611,7 +612,7 @@ void CTxMemPool::pruneSpent(const uint256 &hashTx, CCoins &coins)
     }
 }
 
-bool CTxMemPool::accept(CCoinsDB& coinsdb, CTransaction &tx, bool fCheckInputs, bool* pfMissingInputs)
+bool CTxMemPool::accept(CTransaction &tx, bool fCheckInputs, bool* pfMissingInputs)
 {
     if (pfMissingInputs)
         *pfMissingInputs = false;
@@ -673,9 +674,7 @@ bool CTxMemPool::accept(CCoinsDB& coinsdb, CTransaction &tx, bool fCheckInputs,
 
     if (fCheckInputs)
     {
-        CCoinsViewDB viewDB(coinsdb);
-        CCoinsViewMemPool viewMemPool(viewDB, mempool);
-        CCoinsViewCache view(viewMemPool);
+        CCoinsViewCache &view = *pcoinsTip;
 
         // do we already have it?
         if (view.HaveCoins(hash))
@@ -764,9 +763,9 @@ bool CTxMemPool::accept(CCoinsDB& coinsdb, CTransaction &tx, bool fCheckInputs,
     return true;
 }
 
-bool CTransaction::AcceptToMemoryPool(CCoinsDB& coinsdb, bool fCheckInputs, bool* pfMissingInputs)
+bool CTransaction::AcceptToMemoryPool(bool fCheckInputs, bool* pfMissingInputs)
 {
-    return mempool.accept(coinsdb, *this, fCheckInputs, pfMissingInputs);
+    return mempool.accept(*this, fCheckInputs, pfMissingInputs);
 }
 
 bool CTxMemPool::addUnchecked(const uint256& hash, CTransaction &tx)
@@ -854,27 +853,21 @@ int CMerkleTx::GetBlocksToMaturity() const
 }
 
 
-bool CMerkleTx::AcceptToMemoryPool(CCoinsDB& coinsdb, bool fCheckInputs)
+bool CMerkleTx::AcceptToMemoryPool(bool fCheckInputs)
 {
     if (fClient)
     {
         if (!IsInMainChain() && !ClientCheckInputs())
             return false;
-        return CTransaction::AcceptToMemoryPool(coinsdb, false);
+        return CTransaction::AcceptToMemoryPool(false);
     }
     else
     {
-        return CTransaction::AcceptToMemoryPool(coinsdb, fCheckInputs);
+        return CTransaction::AcceptToMemoryPool(fCheckInputs);
     }
 }
 
-bool CMerkleTx::AcceptToMemoryPool()
-{
-    CCoinsDB coinsdb("r");
-    return AcceptToMemoryPool(coinsdb);
-}
-
-bool CWalletTx::AcceptWalletTransaction(CCoinsDB& coinsdb, bool fCheckInputs)
+bool CWalletTx::AcceptWalletTransaction(bool fCheckInputs)
 {
 
     {
@@ -885,21 +878,15 @@ bool CWalletTx::AcceptWalletTransaction(CCoinsDB& coinsdb, bool fCheckInputs)
             if (!(tx.IsCoinBase() || tx.IsCoinStake()))
             {
                 uint256 hash = tx.GetHash();
-                if (!mempool.exists(hash) && !coinsdb.HaveCoins(hash))
-                    tx.AcceptToMemoryPool(coinsdb, fCheckInputs);
+                if (!mempool.exists(hash) && pcoinsTip->HaveCoins(hash))
+                    tx.AcceptToMemoryPool(fCheckInputs);
             }
         }
-        return AcceptToMemoryPool(coinsdb, fCheckInputs);
+        return AcceptToMemoryPool(fCheckInputs);
     }
     return false;
 }
 
-bool CWalletTx::AcceptWalletTransaction()
-{
-    CCoinsDB coinsdb("r");
-    return AcceptWalletTransaction(coinsdb);
-}
-
 // Return transaction in tx, and if it was found inside a block, its hash is placed in hashBlock
 bool GetTransaction(const uint256 &hash, CTransaction &txOut, uint256 &hashBlock, bool fAllowSlow)
 {
@@ -918,8 +905,7 @@ bool GetTransaction(const uint256 &hash, CTransaction &txOut, uint256 &hashBlock
         if (fAllowSlow) { // use coin database to locate block that contains transaction, and scan it
             int nHeight = -1;
             {
-                CCoinsDB coindb("r");
-                CCoinsViewDB view(coindb);
+                CCoinsViewCache &view = *pcoinsTip;
                 CCoins coins;
                 if (view.GetCoins(hash, coins))
                     nHeight = coins.nHeight;
@@ -1441,7 +1427,7 @@ bool CTransaction::CheckInputs(CCoinsView &inputs, enum CheckSig_mode csmode, bo
 
             // Coin stake tx earns reward instead of paying fee
             uint64 nCoinAge;
-            if (!GetCoinAge(inputs, nCoinAge))
+            if (!GetCoinAge(nCoinAge))
                 return error("CheckInputs() : %s unable to get coin age for coinstake", GetHash().ToString().substr(0,10).c_str());
 
             int64 nStakeReward = GetValueOut() - nValueIn;
@@ -1747,18 +1733,15 @@ bool CBlock::ConnectBlock(CBlockIndex* pindex, CCoinsView &view, bool fJustCheck
 
 bool CBlock::SetBestChain(CBlockIndex* pindexNew)
 {
-    // if this functions exits prematurely, the transaction is aborted
-    CCoinsDB coinsdb;
-    if (!coinsdb.TxnBegin())
-        return error("SetBestChain() : TxnBegin failed");
+    CCoinsViewCache &view = *pcoinsTip;
 
     // special case for attaching the genesis block
     // note that no ConnectBlock is called, so its coinbase output is non-spendable
     if (pindexGenesisBlock == NULL && pindexNew->GetBlockHash() == (!fTestNet ? hashGenesisBlock : hashGenesisBlockTestNet))
     {
-        coinsdb.WriteHashBestChain(pindexNew->GetBlockHash());
-        if (!coinsdb.TxnCommit())
-            return error("SetBestChain() : TxnCommit failed");
+        view.SetBestBlock(pindexNew);
+        if (!view.Flush())
+            return false;
         pindexGenesisBlock = pindexNew;
         pindexBest = pindexNew;
         hashBestChain = pindexNew->GetBlockHash();
@@ -1767,10 +1750,6 @@ bool CBlock::SetBestChain(CBlockIndex* pindexNew)
         return true;
     }
 
-    // create cached view to the coins database
-    CCoinsViewDB viewDB(coinsdb);
-    CCoinsViewCache view(viewDB);
-
     // Find the fork (typically, there is none)
     CBlockIndex* pfork = view.GetBestBlock();
     CBlockIndex* plonger = pindexNew;
@@ -1807,8 +1786,11 @@ bool CBlock::SetBestChain(CBlockIndex* pindexNew)
         CBlock block;
         if (!block.ReadFromDisk(pindex))
             return error("SetBestBlock() : ReadFromDisk for disconnect failed");
-        if (!block.DisconnectBlock(pindex, view))
+        CCoinsViewCache viewTemp(view, true);
+        if (!block.DisconnectBlock(pindex, viewTemp))
             return error("SetBestBlock() : DisconnectBlock %s failed", pindex->GetBlockHash().ToString().substr(0,20).c_str());
+        if (!viewTemp.Flush())
+            return error("SetBestBlock() : Cache flush failed after disconnect");
 
         // Queue memory transactions to resurrect
         BOOST_FOREACH(const CTransaction& tx, block.vtx)
@@ -1828,10 +1810,13 @@ bool CBlock::SetBestChain(CBlockIndex* pindexNew)
                 return error("SetBestBlock() : ReadFromDisk for connect failed");
             pblock = &block;
         }
-        if (!pblock->ConnectBlock(pindex, view)) {
+        CCoinsViewCache viewTemp(view, true);
+        if (!pblock->ConnectBlock(pindex, viewTemp)) {
             InvalidChainFound(pindexNew);
             return error("SetBestBlock() : ConnectBlock %s failed", pindex->GetBlockHash().ToString().substr(0,20).c_str());
         }
+        if (!viewTemp.Flush())
+            return error("SetBestBlock() : Cache flush failed after connect");
 
         // Queue memory transactions to delete
         BOOST_FOREACH(const CTransaction& tx, pblock->vtx)
@@ -1839,11 +1824,10 @@ bool CBlock::SetBestChain(CBlockIndex* pindexNew)
     }
 
     // Make sure it's successfully written to disk before changing memory structure
-    if (!view.Flush())
-        return error("SetBestBlock() : failed to write coin changes");
-    if (!coinsdb.TxnCommit())
-        return error("SetBestBlock() : TxnCommit failed");
-    coinsdb.Close();
+    bool fIsInitialDownload = IsInitialBlockDownload();
+    if (!fIsInitialDownload || view.GetCacheSize()>5000)
+        if (!view.Flush())
+            return false;
 
     // At this point, all changes have been done to the database.
     // Proceed by updating the memory structures.
@@ -1860,14 +1844,13 @@ bool CBlock::SetBestChain(CBlockIndex* pindexNew)
 
     // Resurrect memory transactions that were in the disconnected branch
     BOOST_FOREACH(CTransaction& tx, vResurrect)
-        tx.AcceptToMemoryPool(coinsdb, false);
+        tx.AcceptToMemoryPool(false);
 
     // Delete redundant memory transactions that are in the connected branch
     BOOST_FOREACH(CTransaction& tx, vDelete)
         mempool.remove(tx);
 
     // Update best block in wallet (so we can detect restored wallets)
-    bool fIsInitialDownload = IsInitialBlockDownload();
     if (!fIsInitialDownload)
     {
         const CBlockLocator locator(pindexNew);
@@ -1927,8 +1910,10 @@ bool CBlock::SetBestChain(CBlockIndex* pindexNew)
 // guaranteed to be in main chain by sync-checkpoint. This rule is
 // introduced to help nodes establish a consistent view of the coin
 // age (trust score) of competing branches.
-bool CTransaction::GetCoinAge(CCoinsView& inputs, uint64& nCoinAge) const
+bool CTransaction::GetCoinAge(uint64& nCoinAge) const
 {
+    CCoinsViewCache &inputs = *pcoinsTip;
+
     CBigNum bnCentSecond = 0;  // coin age in the unit of cent-seconds
     nCoinAge = 0;
 
@@ -1965,13 +1950,10 @@ bool CBlock::GetCoinAge(uint64& nCoinAge) const
 {
     nCoinAge = 0;
 
-    CCoinsDB coindb("r");
-    CCoinsViewDB view(coindb);
-
     BOOST_FOREACH(const CTransaction& tx, vtx)
     {
         uint64 nTxCoinAge;
-        if (tx.GetCoinAge(view, nTxCoinAge))
+        if (tx.GetCoinAge(nTxCoinAge))
             nCoinAge += nTxCoinAge;
         else
             return false;
@@ -2037,11 +2019,8 @@ bool CBlock::AddToBlockIndex(const CDiskBlockPos &pos)
         return false;
 
     // New best
-    if (pindexNew->nChainTrust > nBestChainTrust) {
-        if (!IsInitialBlockDownload() || (pindexNew->nHeight % 1) == 0)
-            if (!SetBestChain(pindexNew))
-                return false;
-    }
+    if (!SetBestChain(pindexNew))
+        return false;
 
     if (pindexNew == pindexBest)
     {
@@ -2729,11 +2708,9 @@ bool LoadBlockIndex(bool fAllowNew)
     // Load block index
     //
     CChainDB chaindb("cr");
-    CCoinsDB coinsdb("cr");
-    if (!LoadBlockIndex(coinsdb, chaindb))
+    if (!LoadBlockIndex(chaindb))
         return false;
     chaindb.Close();
-    coinsdb.Close();
 
     //
     // Init with genesis block
@@ -3041,7 +3018,7 @@ string GetWarnings(string strFor)
 //
 
 
-bool static AlreadyHave(CCoinsDB &coinsdb, const CInv& inv)
+bool static AlreadyHave(const CInv& inv)
 {
     switch (inv.type)
     {
@@ -3053,7 +3030,7 @@ bool static AlreadyHave(CCoinsDB &coinsdb, const CInv& inv)
                 txInMap = mempool.exists(inv.hash);
             }
             return txInMap || mapOrphanTransactions.count(inv.hash) ||
-                coinsdb.HaveCoins(inv.hash);
+                pcoinsTip->HaveCoins(inv.hash);
         }
     case MSG_BLOCK:
         return mapBlockIndex.count(inv.hash) ||
@@ -3306,7 +3283,6 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
                 break;
             }
         }
-        CCoinsDB coinsdb("r");
         for (unsigned int nInv = 0; nInv < vInv.size(); nInv++)
         {
             const CInv &inv = vInv[nInv];
@@ -3315,7 +3291,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
                 return true;
             pfrom->AddInventoryKnown(inv);
 
-            bool fAlreadyHave = AlreadyHave(coinsdb, inv);
+            bool fAlreadyHave = AlreadyHave(inv);
             if (fDebug)
                 printf("  got inventory: %s  %s\n", inv.ToString().c_str(), fAlreadyHave ? "have" : "new");
 
@@ -3503,7 +3479,6 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
         vector<uint256> vWorkQueue;
         vector<uint256> vEraseQueue;
         CDataStream vMsg(vRecv);
-        CCoinsDB coinsdb("r");
         CTransaction tx;
         vRecv >> tx;
 
@@ -3511,7 +3486,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
         pfrom->AddInventoryKnown(inv);
 
         bool fMissingInputs = false;
-        if (tx.AcceptToMemoryPool(coinsdb, true, &fMissingInputs))
+        if (tx.AcceptToMemoryPool(true, &fMissingInputs))
         {
             SyncWithWallets(tx, NULL, true);
             RelayTransaction(tx, inv.hash);
@@ -3531,7 +3506,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
                     CTransaction& orphanTx = mapOrphanTransactions[orphanTxHash];
                     bool fMissingInputs2 = false;
 
-                    if (orphanTx.AcceptToMemoryPool(coinsdb, true, &fMissingInputs2))
+                    if (orphanTx.AcceptToMemoryPool(true, &fMissingInputs2))
                     {
                         printf("   accepted orphan tx %s\n", orphanTxHash.ToString().substr(0,10).c_str());
                         SyncWithWallets(tx, NULL, true);
@@ -3983,11 +3958,10 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
         //
         vector<CInv> vGetData;
         int64 nNow = GetTime() * 1000000;
-        CCoinsDB coinsdb("r");
         while (!pto->mapAskFor.empty() && (*pto->mapAskFor.begin()).first <= nNow)
         {
             const CInv& inv = (*pto->mapAskFor.begin()).second;
-            if (!AlreadyHave(coinsdb, inv))
+            if (!AlreadyHave(inv))
             {
                 if (fDebugNet)
                     printf("sending getdata: %s\n", inv.ToString().c_str());
index 9eeafcd..b5c770a 100644 (file)
@@ -637,8 +637,8 @@ public:
     bool CheckTransaction() const;
 
     // Try to accept this transaction into the memory pool
-    bool AcceptToMemoryPool(CCoinsDB& coinsdb, bool fCheckInputs=true, bool* pfMissingInputs=NULL);
-    bool GetCoinAge(CCoinsView& inputs, uint64& nCoinAge) const;  // Get transaction coin age
+    bool AcceptToMemoryPool(bool fCheckInputs=true, bool* pfMissingInputs=NULL);
+    bool GetCoinAge(uint64& nCoinAge) const;  // Get transaction coin age
 protected:
     static CTxOut GetOutputFor(const CTxIn& input, CCoinsView& mapInputs);
 };
@@ -1103,8 +1103,7 @@ public:
     int GetDepthInMainChain() const { CBlockIndex *pindexRet; return GetDepthInMainChain(pindexRet); }
     bool IsInMainChain() const { return GetDepthInMainChain() > 0; }
     int GetBlocksToMaturity() const;
-    bool AcceptToMemoryPool(CCoinsDB& txdb, bool fCheckInputs=true);
-    bool AcceptToMemoryPool();
+    bool AcceptToMemoryPool(bool fCheckInputs=true);
 };
 
 
@@ -1933,8 +1932,7 @@ public:
     std::map<uint256, CTransaction> mapTx;
     std::map<COutPoint, CInPoint> mapNextTx;
 
-    bool accept(CCoinsDB& coinsdb, CTransaction &tx,
-                bool fCheckInputs, bool* pfMissingInputs);
+    bool accept(CTransaction &tx, bool fCheckInputs, bool* pfMissingInputs);
     bool addUnchecked(const uint256& hash, CTransaction &tx);
     bool remove(CTransaction &tx);
     void clear();
@@ -1979,6 +1977,7 @@ public:
 
     // Modify the currently active block index
     virtual bool SetBestBlock(CBlockIndex *pindex);
+    virtual bool BatchWrite(const std::map<uint256, CCoins> &mapCoins, CBlockIndex *pindex);
 };
 
 /** CCoinsView backed by another CCoinsView */
@@ -1995,21 +1994,7 @@ public:
     CBlockIndex *GetBestBlock();
     bool SetBestBlock(CBlockIndex *pindex);
     void SetBackend(CCoinsView &viewIn);
-};
-
-
-/** CCoinsView backed by a CCoinsDB */
-class CCoinsViewDB : public CCoinsView
-{
-protected:
-    CCoinsDB &db;
-public:
-    CCoinsViewDB(CCoinsDB &dbIn);
-    bool GetCoins(uint256 txid, CCoins &coins);
-    bool SetCoins(uint256 txid, const CCoins &coins);
-    bool HaveCoins(uint256 txid);
-    CBlockIndex *GetBestBlock();
-    bool SetBestBlock(CBlockIndex *pindex);
+    bool BatchWrite(const std::map<uint256, CCoins> &mapCoins, CBlockIndex *pindex);
 };
 
 /** CCoinsView that adds a memory cache for transactions to another CCoinsView */
@@ -2026,7 +2011,9 @@ public:
     bool HaveCoins(uint256 txid);
     CBlockIndex *GetBestBlock();
     bool SetBestBlock(CBlockIndex *pindex);
+    bool BatchWrite(const std::map<uint256, CCoins> &mapCoins, CBlockIndex *pindex);
     bool Flush();
+    unsigned int GetCacheSize();
 };
 
 /** CCoinsView that brings transactions from a memorypool into view.
@@ -2042,4 +2029,6 @@ public:
     bool HaveCoins(uint256 txid);
 };
 
+extern CCoinsViewCache *pcoinsTip;
+
 #endif
index ca5a132..7c494fa 100644 (file)
@@ -166,9 +166,7 @@ CBlock* CreateNewBlock(CWallet* pwallet, bool fProofOfStake)
     int64 nFees = 0;
     {
         LOCK2(cs_main, mempool.cs);
-        CCoinsDB coinsdb("r");
-        CCoinsViewDB viewdb(coinsdb);
-        CCoinsViewCache view(viewdb);
+        CCoinsViewCache view(*pcoinsTip, true);
 
         // Priority order to process transactions
         list<COrphan> vOrphan; // list memory doesn't move
index 32700e3..ccd5ad1 100644 (file)
@@ -234,9 +234,6 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx)
             strHTML += "<br><b>" + tr("Transaction") + ":</b><br>";
             strHTML += GUIUtil::HtmlEscape(wtx.ToString(), true);
 
-            CCoinsDB coinsdb("r"); // To fetch source txouts
-            CCoinsViewDB coins(coinsdb);
-
             strHTML += "<br><b>" + tr("Inputs") + ":</b>";
             strHTML += "<ul>";
 
@@ -247,7 +244,7 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx)
                     COutPoint prevout = txin.prevout;
 
                     CCoins prev;
-                    if(coins.GetCoins(prevout.hash, prev))
+                    if(pcoinsTip->GetCoins(prevout.hash, prev))
                     {
                         if (prevout.n < prev.vout.size())
                         {
index 6ba5a0d..72b850e 100644 (file)
@@ -366,9 +366,7 @@ Value getblocktemplate(const Array& params, bool fHelp)
     Array transactions;
     map<uint256, int64_t> setTxIndex;
     int i = 0;
-    CCoinsDB coindb("r");
-    CCoinsViewDB viewdb(coindb);
-    CCoinsViewCache view(viewdb);
+    CCoinsViewCache &view = *pcoinsTip;
     BOOST_FOREACH (CTransaction& tx, pblock->vtx)
     {
         uint256 txHash = tx.GetHash();
index 203583e..dc32217 100644 (file)
@@ -372,9 +372,8 @@ Value signrawtransaction(const Array& params, bool fHelp)
     CCoinsViewCache view(viewDummy);
     {
         LOCK(mempool.cs);
-        CCoinsDB coinsdb("r");
-        CCoinsViewDB viewDB(coinsdb);
-        CCoinsViewMemPool viewMempool(viewDB, mempool);
+        CCoinsViewCache &viewChain = *pcoinsTip;
+        CCoinsViewMemPool viewMempool(viewChain, mempool);
         view.SetBackend(viewMempool); // temporarily switch cache backend to db+mempool view
 
         BOOST_FOREACH(const CTxIn& txin, mergedTx.vin) {
@@ -383,7 +382,7 @@ Value signrawtransaction(const Array& params, bool fHelp)
             view.GetCoins(prevHash, coins); // this is certainly allowed to fail
         }
 
-        view.SetBackend(viewDummy); // switch back to avoid locking db/mempool too long
+        view.SetBackend(viewDummy); // switch back to avoid locking mempool for too long
     }
 
     // Add previous txouts given in the RPC call:
@@ -535,17 +534,13 @@ Value sendrawtransaction(const Array& params, bool fHelp)
     uint256 hashTx = tx.GetHash();
 
     bool fHave = false;
+    CCoinsViewCache &view = *pcoinsTip;
     CCoins existingCoins;
     {
-        CCoinsDB coinsdb("r");
-        {
-            CCoinsViewDB coinsviewDB(coinsdb);
-            CCoinsViewMemPool coinsview(coinsviewDB, mempool);
-            fHave = coinsview.GetCoins(hashTx, existingCoins);
-        }
+        fHave = view.GetCoins(hashTx, existingCoins);
         if (!fHave) {
             // push to local node
-            if (!tx.AcceptToMemoryPool(coinsdb))
+            if (!tx.AcceptToMemoryPool())
                 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX rejected");
         }
     }
index 20bedc5..86b4a30 100644 (file)
@@ -821,7 +821,6 @@ int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate)
 
 void CWallet::ReacceptWalletTransactions()
 {
-    CCoinsDB coinsdb("r");
     bool fRepeat = true;
     while (fRepeat)
     {
@@ -836,7 +835,7 @@ void CWallet::ReacceptWalletTransactions()
 
             CCoins coins;
             bool fUpdated = false;
-            bool fNotFound = coinsdb.ReadCoins(wtx.GetHash(), coins);
+            bool fNotFound = pcoinsTip->GetCoins(wtx.GetHash(), coins);
             if (!fNotFound || wtx.GetDepthInMainChain() > 0)
             {
                 // Update fSpent if a tx got spent somewhere else by a copy of wallet.dat
@@ -862,7 +861,7 @@ void CWallet::ReacceptWalletTransactions()
             {
                 // Re-accept any txes of ours that aren't already in a block
                 if (!wtx.IsCoinBase())
-                    wtx.AcceptWalletTransaction(coinsdb, false);
+                    wtx.AcceptWalletTransaction(false);
             }
         }
         if (fMissing)
@@ -874,21 +873,22 @@ void CWallet::ReacceptWalletTransactions()
     }
 }
 
-void CWalletTx::RelayWalletTransaction(CCoinsDB& coinsdb)
+void CWalletTx::RelayWalletTransaction()
 {
+    CCoinsViewCache& coins = *pcoinsTip;
     BOOST_FOREACH(const CMerkleTx& tx, vtxPrev)
     {
         if (!tx.IsCoinBase())
         {
             uint256 hash = tx.GetHash();
-            if (!coinsdb.HaveCoins(hash))
+            if (!coins.HaveCoins(hash))
                 RelayTransaction((CTransaction)tx, hash);
         }
     }
     if (!IsCoinBase())
     {
         uint256 hash = GetHash();
-        if (!coinsdb.HaveCoins(hash))
+        if (!coins.HaveCoins(hash))
         {
             printf("Relaying wtx %s\n", hash.ToString().substr(0,10).c_str());
             RelayTransaction((CTransaction)*this, hash);
@@ -896,12 +896,6 @@ void CWalletTx::RelayWalletTransaction(CCoinsDB& coinsdb)
     }
 }
 
-void CWalletTx::RelayWalletTransaction()
-{
-   CCoinsDB coinsdb("r");
-   RelayWalletTransaction(coinsdb);
-}
-
 void CWallet::ResendWalletTransactions()
 {
     // Do this infrequently and randomly to avoid giving away
@@ -922,7 +916,6 @@ void CWallet::ResendWalletTransactions()
 
     // Rebroadcast any of our txes that aren't in a block yet
     printf("ResendWalletTransactions()\n");
-    CCoinsDB coinsdb("r");
     {
         LOCK(cs_wallet);
         // Sort them in chronological order
@@ -938,7 +931,7 @@ void CWallet::ResendWalletTransactions()
         BOOST_FOREACH(PAIRTYPE(const unsigned int, CWalletTx*)& item, mapSorted)
         {
             CWalletTx& wtx = *item.second;
-            wtx.RelayWalletTransaction(coinsdb);
+            wtx.RelayWalletTransaction();
         }
     }
 }
@@ -1475,8 +1468,7 @@ bool CWallet::GetStakeWeight(const CKeyStore& keystore, uint64& nMinWeight, uint
     if (setCoins.empty())
         return false;
 
-    CCoinsDB coinsdb("r");
-    CCoinsViewDB view(coinsdb);
+    CCoinsViewCache &view = *pcoinsTip;
     BOOST_FOREACH(PAIRTYPE(const CWalletTx*, unsigned int) pcoin, setCoins)
     {
         CCoins coins;
@@ -1573,8 +1565,7 @@ bool CWallet::CreateCoinStake(const CKeyStore& keystore, unsigned int nBits, int
     int64 nCredit = 0;
     CScript scriptPubKeyKernel;
 
-    CCoinsDB coinsdb("r");
-    CCoinsViewDB view(coinsdb);
+    CCoinsViewCache &view = *pcoinsTip;
     BOOST_FOREACH(PAIRTYPE(const CWalletTx*, unsigned int) pcoin, setCoins)
     {
         CCoins coins;
@@ -1726,10 +1717,7 @@ bool CWallet::CreateCoinStake(const CKeyStore& keystore, unsigned int nBits, int
     {
         uint64 nCoinAge;
 
-        CCoinsDB coindb("r");
-        CCoinsViewDB view(coindb);
-
-        if (!txNew.GetCoinAge(view, nCoinAge))
+        if (!txNew.GetCoinAge(nCoinAge))
             return error("CreateCoinStake : failed to calculate coin age");
         nCredit += GetProofOfStakeReward(nCoinAge, nBits, txNew.nTime);
     }
@@ -2281,13 +2269,13 @@ void CWallet::FixSpentCoins(int& nMismatchFound, int64& nBalanceInQuestion, bool
     for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
         vCoins.push_back(&(*it).second);
 
-    CCoinsDB coinsdb("r");
+    CCoinsViewCache &view = *pcoinsTip;
     BOOST_FOREACH(CWalletTx* pcoin, vCoins)
     {
         // Find the corresponding transaction index
         CCoins coins;
 
-        bool fNotFound = coinsdb.ReadCoins(pcoin->GetHash(), coins);
+        bool fNotFound = view.GetCoins(pcoin->GetHash(), coins);
 
         for (unsigned int n=0; n < pcoin->vout.size(); n++)
         {
index c134a29..a3ead62 100644 (file)
@@ -690,10 +690,7 @@ public:
 
     void AddSupportingTransactions();
 
-    bool AcceptWalletTransaction(CCoinsDB& coinsdb, bool fCheckInputs=true);
-    bool AcceptWalletTransaction();
-
-    void RelayWalletTransaction(CCoinsDB& coinsdb);
+    bool AcceptWalletTransaction(bool fCheckInputs=true);
     void RelayWalletTransaction();
 };