From ae8bfd12daa802d20791e69d3477e799d2b99f45 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Fri, 6 Jul 2012 16:33:34 +0200 Subject: [PATCH] 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. --- src/db.cpp | 89 ++++++++++++++++------ src/db.h | 20 ++++- src/init.cpp | 12 +++ src/main.cpp | 150 +++++++++++++++---------------------- src/main.h | 30 +++----- src/qt/transactiondesc.cpp | 5 +- src/rpcmining.cpp | 4 +- src/rpcrawtransaction.cpp | 17 ++--- src/wallet.cpp | 21 ++---- src/wallet.h | 6 +- 10 files changed, 183 insertions(+), 171 deletions(-) diff --git a/src/db.cpp b/src/db.cpp index 0a6ba3fb3..06e5543b2 100644 --- a/src/db.cpp +++ b/src/db.cpp @@ -79,8 +79,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); @@ -279,14 +279,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; @@ -298,6 +294,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); @@ -537,6 +545,42 @@ 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::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 &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::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 @@ CBlockIndex static * InsertBlockIndex(uint256 hash) return pindexNew; } -bool LoadBlockIndex(CCoinsDB &coindb, CChainDB &chaindb) +bool LoadBlockIndex(CChainDB &chaindb) { if (!chaindb.LoadBlockIndexGuts()) return false; @@ -587,26 +631,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::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, diff --git a/src/db.h b/src/db.h index dd8993d56..bdab63546 100644 --- 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 &mapCoins, CBlockIndex *pindex); +}; + + /** Access to the block database (chain.dat) */ class CChainDB : public CDB { @@ -350,7 +368,7 @@ public: }; -bool LoadBlockIndex(CCoinsDB &coinsdb, CChainDB &chaindb); +bool LoadBlockIndex(CChainDB &chaindb); /** Access to the (IP) address database (peers.dat) */ diff --git a/src/init.cpp b/src/init.cpp index 56108cece..b05d57abf 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -50,6 +50,8 @@ void StartShutdown() #endif } +static CCoinsViewDB *pcoinsdbview; + void Shutdown(void* parg) { static CCriticalSection cs_Shutdown; @@ -74,6 +76,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); @@ -298,6 +306,7 @@ std::string HelpMessage() return strUsage; } + /** Initialize bitcoin. * @pre Parameters should be parsed and config file should be read. */ @@ -641,6 +650,9 @@ 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")); diff --git a/src/main.cpp b/src/main.cpp index ef5f627d9..c23aae320 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -168,6 +168,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 &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 @@ bool CCoinsViewBacked::HaveCoins(uint256 txid) { return base->HaveCoins(txid); } 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 &mapCoins, CBlockIndex *pindex) { return base->BatchWrite(mapCoins, pindex); } CCoinsViewCache::CCoinsViewCache(CCoinsView &baseIn, bool fDummy) : CCoinsViewBacked(baseIn), pindexTip(NULL) { } @@ -218,18 +213,24 @@ bool CCoinsViewCache::SetBestBlock(CBlockIndex *pindex) { return true; } -bool CCoinsViewCache::Flush() { - for (std::map::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 &mapCoins, CBlockIndex *pindex) { + for (std::map::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) { } @@ -249,7 +250,7 @@ bool CCoinsViewMemPool::HaveCoins(uint256 txid) { return mempool.exists(txid) || base->HaveCoins(txid); } - +CCoinsViewCache *pcoinsTip = NULL; ////////////////////////////////////////////////////////////////////////////// // @@ -450,9 +451,8 @@ int CMerkleTx::SetMerkleBranch(const CBlock* pblock) 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 @@ void CTxMemPool::pruneSpent(const uint256 &hashTx, CCoins &coins) } } -bool CTxMemPool::accept(CCoinsDB& coinsdb, CTransaction &tx, bool fCheckInputs, +bool CTxMemPool::accept(CTransaction &tx, bool fCheckInputs, bool* pfMissingInputs) { if (pfMissingInputs) @@ -668,9 +668,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)) @@ -758,9 +756,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) @@ -849,31 +847,24 @@ 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() + + +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 @@ bool CWalletTx::AcceptWalletTransaction(CCoinsDB& coinsdb, bool fCheckInputs) 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 @@ 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; @@ -1565,18 +1550,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() == 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 @@ 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; @@ -1625,8 +1603,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) @@ -1646,10 +1627,13 @@ bool CBlock::SetBestChain(CBlockIndex* pindexNew) return error("SetBestBlock() : ReadFromDisk for connect failed"); pblock = █ } - 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 @@ 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. @@ -1678,14 +1661,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); @@ -1765,11 +1747,8 @@ bool CBlock::AddToBlockIndex(const CDiskBlockPos &pos) 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 @@ 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 @@ -2492,7 +2469,7 @@ string GetWarnings(string strFor) // -bool static AlreadyHave(CCoinsDB &coinsdb, const CInv& inv) +bool static AlreadyHave(const CInv& inv) { switch (inv.type) { @@ -2504,7 +2481,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) || @@ -2748,7 +2725,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]; @@ -2757,7 +2733,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"); @@ -2929,7 +2905,6 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) vector vWorkQueue; vector vEraseQueue; CDataStream vMsg(vRecv); - CCoinsDB coinsdb("r"); CTransaction tx; vRecv >> tx; @@ -2937,7 +2912,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); RelayMessage(inv, vMsg); @@ -2959,7 +2934,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) 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 @@ bool SendMessages(CNode* pto, bool fSendTrickle) // vector 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 @@ CBlock* CreateNewBlock(CReserveKey& reservekey) 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 vOrphan; // list memory doesn't move @@ -3811,7 +3783,7 @@ CBlock* CreateNewBlock(CReserveKey& reservekey) 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"); } diff --git a/src/main.h b/src/main.h index a57fadac7..0ec68b612 100644 --- a/src/main.h +++ b/src/main.h @@ -583,7 +583,7 @@ public: 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 @@ public: bool WriteToDisk(CDiskBlockPos &pos) { + // Open history file to append CAutoFile fileout = CAutoFile(OpenUndoFile(pos), SER_DISK, CLIENT_VERSION); if (!fileout) @@ -995,8 +996,7 @@ public: 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 @@ public: std::map mapTx; std::map 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 @@ public: // Modify the currently active block index virtual bool SetBestBlock(CBlockIndex *pindex); + virtual bool BatchWrite(const std::map &mapCoins, CBlockIndex *pindex); }; /** CCoinsView backed by another CCoinsView */ @@ -1738,21 +1738,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 &mapCoins, CBlockIndex *pindex); }; /** CCoinsView that adds a memory cache for transactions to another CCoinsView */ @@ -1769,7 +1755,9 @@ public: bool HaveCoins(uint256 txid); CBlockIndex *GetBestBlock(); bool SetBestBlock(CBlockIndex *pindex); + bool BatchWrite(const std::map &mapCoins, CBlockIndex *pindex); bool Flush(); + unsigned int GetCacheSize(); }; /** CCoinsView that brings transactions from a memorypool into view. @@ -1785,4 +1773,6 @@ public: bool HaveCoins(uint256 txid); }; +extern CCoinsViewCache *pcoinsTip; + #endif diff --git a/src/qt/transactiondesc.cpp b/src/qt/transactiondesc.cpp index dc840b9f8..e358c12e9 100644 --- a/src/qt/transactiondesc.cpp +++ b/src/qt/transactiondesc.cpp @@ -234,9 +234,6 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx) strHTML += "
" + tr("Transaction") + ":
"; strHTML += GUIUtil::HtmlEscape(wtx.ToString(), true); - CCoinsDB coindb("r"); // To fetch source txouts - CCoinsViewDB coins(coindb); - strHTML += "
" + tr("Inputs") + ":"; strHTML += "
    "; @@ -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()) { diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp index 96518c6d8..0270b5f10 100644 --- a/src/rpcmining.cpp +++ b/src/rpcmining.cpp @@ -281,9 +281,7 @@ Value getblocktemplate(const Array& params, bool fHelp) Array transactions; map 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(); diff --git a/src/rpcrawtransaction.cpp b/src/rpcrawtransaction.cpp index c62898316..647384f33 100644 --- a/src/rpcrawtransaction.cpp +++ b/src/rpcrawtransaction.cpp @@ -339,9 +339,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) { @@ -350,7 +349,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: @@ -502,17 +501,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"); } } diff --git a/src/wallet.cpp b/src/wallet.cpp index 9b2960f64..5b3203469 100644 --- a/src/wallet.cpp +++ b/src/wallet.cpp @@ -767,7 +767,6 @@ int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate) void CWallet::ReacceptWalletTransactions() { - CCoinsDB coinsdb("r"); bool fRepeat = true; while (fRepeat) { @@ -782,7 +781,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 @@ -808,7 +807,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) @@ -820,21 +819,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)) 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) } } -void CWalletTx::RelayWalletTransaction() -{ - CCoinsDB coinsdb("r"); - RelayWalletTransaction(coinsdb); -} - void CWallet::ResendWalletTransactions() { // Do this infrequently and randomly to avoid giving away @@ -868,7 +862,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 @@ -884,7 +877,7 @@ void CWallet::ResendWalletTransactions() BOOST_FOREACH(PAIRTYPE(const unsigned int, CWalletTx*)& item, mapSorted) { CWalletTx& wtx = *item.second; - wtx.RelayWalletTransaction(coinsdb); + wtx.RelayWalletTransaction(); } } } diff --git a/src/wallet.h b/src/wallet.h index e0aa07797..8c98f34a5 100644 --- a/src/wallet.h +++ b/src/wallet.h @@ -659,11 +659,7 @@ public: 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(); };