changeset 3650:12e3ba3a9c4b draft

Batch block connection during IBD During the initial block download (or -loadblock), delay connection of new blocks a bit, and perform them in a single action. This reduces the load on the database engine, as subsequent blocks often update an earlier block's transaction already.
author Pieter Wuille <pieter.wuille@gmail.com>
date Fri, 06 Jul 2012 16:33:34 +0200
parents eb986f1e2e93
children 17828f292f78
files src/db.cpp src/db.h src/init.cpp src/main.cpp src/main.h src/qt/transactiondesc.cpp src/rpcmining.cpp src/rpcrawtransaction.cpp src/wallet.cpp src/wallet.h
diffstat 10 files changed, 183 insertions(+), 171 deletions(-) [+]
line wrap: on
line diff
--- a/src/db.cpp
+++ b/src/db.cpp
@@ -79,8 +79,8 @@
     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);
@@ -279,14 +279,10 @@
     return false;
 }
 
-void CDB::Close()
+void CDB::Flush()
 {
-    if (!pdb)
+    if (activeTxn)
         return;
-    if (activeTxn)
-        activeTxn->abort();
-    activeTxn = NULL;
-    pdb = NULL;
 
     // Flush database activity from memory pool to disk log
     unsigned int nMinutes = 0;
@@ -298,6 +294,18 @@
         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);
@@ -537,6 +545,42 @@
     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)
@@ -557,7 +601,7 @@
     return pindexNew;
 }
 
-bool LoadBlockIndex(CCoinsDB &coindb, CChainDB &chaindb)
+bool LoadBlockIndex(CChainDB &chaindb)
 {
     if (!chaindb.LoadBlockIndexGuts())
         return false;
@@ -587,26 +631,23 @@
         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;
-        bnBestChainWork = pindexBest->bnChainWork;
+    hashBestChain = pindexBest->GetBlockHash();
+    nBestHeight = pindexBest->nHeight;
+    bnBestChainWork = pindexBest->bnChainWork;
+
+    // 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,
--- a/src/db.h
+++ b/src/db.h
@@ -102,6 +102,7 @@
     explicit CDB(const char* pszFile, const char* pszMode="r+");
     ~CDB() { Close(); }
 public:
+    void Flush();
     void Close();
 private:
     CDB(const CDB&);
@@ -330,6 +331,23 @@
     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
 {
@@ -350,7 +368,7 @@
 };
 
 
-bool LoadBlockIndex(CCoinsDB &coinsdb, CChainDB &chaindb);
+bool LoadBlockIndex(CChainDB &chaindb);
 
 
 /** Access to the (IP) address database (peers.dat) */
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -50,6 +50,8 @@
 #endif
 }
 
+static CCoinsViewDB *pcoinsdbview;
+
 void Shutdown(void* parg)
 {
     static CCriticalSection cs_Shutdown;
@@ -74,6 +76,12 @@
         nTransactionsUpdated++;
         bitdb.Flush(false);
         StopNode();
+        {
+            LOCK(cs_main);
+            pcoinsTip->Flush();
+            delete pcoinsTip;
+            delete pcoinsdbview;
+        }
         bitdb.Flush(true);
         boost::filesystem::remove(GetPidFile());
         UnregisterWallet(pwalletMain);
@@ -298,6 +306,7 @@
     return strUsage;
 }
 
+
 /** Initialize bitcoin.
  *  @pre Parameters should be parsed and config file should be read.
  */
@@ -641,6 +650,9 @@
     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"));
 
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -168,6 +168,7 @@
 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); }
@@ -176,13 +177,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) { }
 
@@ -218,16 +213,22 @@
     return true;
 }
 
+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() {
-    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;
-    return true;
+    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.
@@ -249,7 +250,7 @@
     return mempool.exists(txid) || base->HaveCoins(txid);
 }
 
-
+CCoinsViewCache *pcoinsTip = NULL;
 
 //////////////////////////////////////////////////////////////////////////////
 //
@@ -450,9 +451,8 @@
         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))
@@ -609,7 +609,7 @@
     }
 }
 
-bool CTxMemPool::accept(CCoinsDB& coinsdb, CTransaction &tx, bool fCheckInputs,
+bool CTxMemPool::accept(CTransaction &tx, bool fCheckInputs,
                         bool* pfMissingInputs)
 {
     if (pfMissingInputs)
@@ -668,9 +668,7 @@
 
     if (fCheckInputs)
     {
-        CCoinsViewDB viewDB(coinsdb);
-        CCoinsViewMemPool viewMemPool(viewDB, mempool);
-        CCoinsViewCache view(viewMemPool);
+        CCoinsViewCache &view = *pcoinsTip;
 
         // do we already have it?
         if (view.HaveCoins(hash))
@@ -758,9 +756,9 @@
     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)
@@ -849,31 +847,24 @@
 }
 
 
-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()
+
+
+bool CWalletTx::AcceptWalletTransaction(bool fCheckInputs)
 {
-    CCoinsDB coinsdb("r");
-    return AcceptToMemoryPool(coinsdb);
-}
-
-
-
-bool CWalletTx::AcceptWalletTransaction(CCoinsDB& coinsdb, bool fCheckInputs)
-{
-
     {
         LOCK(mempool.cs);
         // Add previous supporting transactions first
@@ -882,20 +873,15 @@
             if (!tx.IsCoinBase())
             {
                 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)
@@ -915,8 +901,7 @@
         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;
@@ -1565,18 +1550,15 @@
 
 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() == hashGenesisBlock)
     {
-        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();
@@ -1585,10 +1567,6 @@
         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;
@@ -1625,8 +1603,11 @@
         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)
@@ -1646,10 +1627,13 @@
                 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)
@@ -1657,11 +1641,10 @@
     }
 
     // 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.
@@ -1678,14 +1661,13 @@
 
     // 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);
@@ -1765,11 +1747,8 @@
         return false;
 
     // New best
-    if (pindexNew->bnChainWork > bnBestChainWork) {
-        if (!IsInitialBlockDownload() || (pindexNew->nHeight % 1) == 0)
-            if (!SetBestChain(pindexNew))
-                return false;
-    }
+    if (!SetBestChain(pindexNew))
+        return false;
 
     if (pindexNew == pindexBest)
     {
@@ -2169,11 +2148,9 @@
     // 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
@@ -2492,7 +2469,7 @@
 //
 
 
-bool static AlreadyHave(CCoinsDB &coinsdb, const CInv& inv)
+bool static AlreadyHave(const CInv& inv)
 {
     switch (inv.type)
     {
@@ -2504,7 +2481,7 @@
                 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) ||
@@ -2748,7 +2725,6 @@
                 break;
             }
         }
-        CCoinsDB coinsdb("r");
         for (unsigned int nInv = 0; nInv < vInv.size(); nInv++)
         {
             const CInv &inv = vInv[nInv];
@@ -2757,7 +2733,7 @@
                 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");
 
@@ -2929,7 +2905,6 @@
         vector<uint256> vWorkQueue;
         vector<uint256> vEraseQueue;
         CDataStream vMsg(vRecv);
-        CCoinsDB coinsdb("r");
         CTransaction tx;
         vRecv >> tx;
 
@@ -2937,7 +2912,7 @@
         pfrom->AddInventoryKnown(inv);
 
         bool fMissingInputs = false;
-        if (tx.AcceptToMemoryPool(coinsdb, true, &fMissingInputs))
+        if (tx.AcceptToMemoryPool(true, &fMissingInputs))
         {
             SyncWithWallets(tx, NULL, true);
             RelayMessage(inv, vMsg);
@@ -2959,7 +2934,7 @@
                     CInv inv(MSG_TX, tx.GetHash());
                     bool fMissingInputs2 = false;
 
-                    if (tx.AcceptToMemoryPool(coinsdb, true, &fMissingInputs2))
+                    if (tx.AcceptToMemoryPool(true, &fMissingInputs2))
                     {
                         printf("   accepted orphan tx %s\n", inv.hash.ToString().substr(0,10).c_str());
                         SyncWithWallets(tx, NULL, true);
@@ -3407,11 +3382,10 @@
         //
         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());
@@ -3621,9 +3595,7 @@
     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
@@ -3811,7 +3783,7 @@
         CBlockIndex indexDummy(*pblock);
         indexDummy.pprev = pindexPrev;
         indexDummy.nHeight = pindexPrev->nHeight + 1;
-        CCoinsViewCache viewNew(viewdb);
+        CCoinsViewCache viewNew(*pcoinsTip, true);
         if (!pblock->ConnectBlock(&indexDummy, viewNew, true))
             throw std::runtime_error("CreateNewBlock() : ConnectBlock failed");
     }
--- a/src/main.h
+++ b/src/main.h
@@ -583,7 +583,7 @@
     bool CheckTransaction() const;
 
     // Try to accept this transaction into the memory pool
-    bool AcceptToMemoryPool(CCoinsDB& coinsdb, bool fCheckInputs=true, bool* pfMissingInputs=NULL);
+    bool AcceptToMemoryPool(bool fCheckInputs=true, bool* pfMissingInputs=NULL);
 
 protected:
     static CTxOut GetOutputFor(const CTxIn& input, CCoinsView& mapInputs);
@@ -682,6 +682,7 @@
 
     bool WriteToDisk(CDiskBlockPos &pos)
     {
+
         // Open history file to append
         CAutoFile fileout = CAutoFile(OpenUndoFile(pos), SER_DISK, CLIENT_VERSION);
         if (!fileout)
@@ -995,8 +996,7 @@
     int GetDepthInMainChain() const { CBlockIndex *pindexRet; return GetDepthInMainChain(pindexRet); }
     bool IsInMainChain() const { return GetDepthInMainChain() > 0; }
     int GetBlocksToMaturity() const;
-    bool AcceptToMemoryPool(CCoinsDB& coinsdb, bool fCheckInputs=true);
-    bool AcceptToMemoryPool();
+    bool AcceptToMemoryPool(bool fCheckInputs=true);
 };
 
 
@@ -1676,8 +1676,7 @@
     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();
@@ -1722,6 +1721,7 @@
 
     // 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 */
@@ -1738,21 +1738,7 @@
     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 */
@@ -1769,7 +1755,9 @@
     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.
@@ -1785,4 +1773,6 @@
     bool HaveCoins(uint256 txid);
 };
 
+extern CCoinsViewCache *pcoinsTip;
+
 #endif
--- a/src/qt/transactiondesc.cpp
+++ b/src/qt/transactiondesc.cpp
@@ -234,9 +234,6 @@
             strHTML += "<br><b>" + tr("Transaction") + ":</b><br>";
             strHTML += GUIUtil::HtmlEscape(wtx.ToString(), true);
 
-            CCoinsDB coindb("r"); // To fetch source txouts
-            CCoinsViewDB coins(coindb);
-
             strHTML += "<br><b>" + tr("Inputs") + ":</b>";
             strHTML += "<ul>";
 
@@ -247,7 +244,7 @@
                     COutPoint prevout = txin.prevout;
 
                     CCoins prev;
-                    if(coins.GetCoins(prevout.hash, prev))
+                    if(pcoinsTip->GetCoins(prevout.hash, prev))
                     {
                         if (prevout.n < prev.vout.size())
                         {
--- a/src/rpcmining.cpp
+++ b/src/rpcmining.cpp
@@ -281,9 +281,7 @@
     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();
--- a/src/rpcrawtransaction.cpp
+++ b/src/rpcrawtransaction.cpp
@@ -339,9 +339,8 @@
     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) {
@@ -350,7 +349,7 @@
             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:
@@ -502,17 +501,13 @@
     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");
         }
     }
--- a/src/wallet.cpp
+++ b/src/wallet.cpp
@@ -767,7 +767,6 @@
 
 void CWallet::ReacceptWalletTransactions()
 {
-    CCoinsDB coinsdb("r");
     bool fRepeat = true;
     while (fRepeat)
     {
@@ -782,7 +781,7 @@
 
             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
@@ -808,7 +807,7 @@
             {
                 // 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)
@@ -820,21 +819,22 @@
     }
 }
 
-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))
                 RelayMessage(CInv(MSG_TX, hash), (CTransaction)tx);
         }
     }
     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());
             RelayMessage(CInv(MSG_TX, hash), (CTransaction)*this);
@@ -842,12 +842,6 @@
     }
 }
 
-void CWalletTx::RelayWalletTransaction()
-{
-   CCoinsDB coinsdb("r");
-   RelayWalletTransaction(coinsdb);
-}
-
 void CWallet::ResendWalletTransactions()
 {
     // Do this infrequently and randomly to avoid giving away
@@ -868,7 +862,6 @@
 
     // 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
@@ -884,7 +877,7 @@
         BOOST_FOREACH(PAIRTYPE(const unsigned int, CWalletTx*)& item, mapSorted)
         {
             CWalletTx& wtx = *item.second;
-            wtx.RelayWalletTransaction(coinsdb);
+            wtx.RelayWalletTransaction();
         }
     }
 }
--- a/src/wallet.h
+++ b/src/wallet.h
@@ -659,11 +659,7 @@
     int GetRequestCount() const;
 
     void AddSupportingTransactions();
-
-    bool AcceptWalletTransaction(CCoinsDB& coinsdb, bool fCheckInputs=true);
-    bool AcceptWalletTransaction();
-
-    void RelayWalletTransaction(CCoinsDB& coinsdb);
+    bool AcceptWalletTransaction(bool fCheckInputs=true);
     void RelayWalletTransaction();
 };