Browse Source

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.
0.8
Pieter Wuille 13 years ago
parent
commit
ae8bfd12da
  1. 79
      src/db.cpp
  2. 20
      src/db.h
  3. 12
      src/init.cpp
  4. 138
      src/main.cpp
  5. 30
      src/main.h
  6. 5
      src/qt/transactiondesc.cpp
  7. 4
      src/rpcmining.cpp
  8. 17
      src/rpcrawtransaction.cpp
  9. 21
      src/wallet.cpp
  10. 6
      src/wallet.h

79
src/db.cpp

@ -79,8 +79,8 @@ bool CDBEnv::Open(boost::filesystem::path pathEnv_) @@ -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) @@ -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() @@ -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) { @@ -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<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 @@ CBlockIndex static * InsertBlockIndex(uint256 hash) @@ -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,27 +631,24 @@ bool LoadBlockIndex(CCoinsDB &coindb, CChainDB &chaindb) @@ -587,27 +631,24 @@ 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 {
hashBestChain = pindexBest->GetBlockHash();
nBestHeight = pindexBest->nHeight;
bnBestChainWork = pindexBest->bnChainWork;
// set 'next' pointers in best chain
CBlockIndex *pindex = it->second;
CBlockIndex *pindex = pindexBest;
while(pindex != NULL && pindex->pprev != NULL) {
CBlockIndex *pindexPrev = pindex->pprev;
pindexPrev->pnext = pindex;
pindex = pindexPrev;
}
pindexBest = it->second;
nBestHeight = pindexBest->nHeight;
bnBestChainWork = pindexBest->bnChainWork;
}
printf("LoadBlockIndex(): hashBestChain=%s height=%d date=%s\n",
hashBestChain.ToString().substr(0,20).c_str(), nBestHeight,
DateTimeStrFormat("%x %H:%M:%S", pindexBest->GetBlockTime()).c_str());

20
src/db.h

@ -102,6 +102,7 @@ protected: @@ -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: @@ -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
{
@ -350,7 +368,7 @@ public: @@ -350,7 +368,7 @@ public:
};
bool LoadBlockIndex(CCoinsDB &coinsdb, CChainDB &chaindb);
bool LoadBlockIndex(CChainDB &chaindb);
/** Access to the (IP) address database (peers.dat) */

12
src/init.cpp

@ -50,6 +50,8 @@ void StartShutdown() @@ -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) @@ -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() @@ -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() @@ -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"));

138
src/main.cpp

@ -168,6 +168,7 @@ bool CCoinsView::SetCoins(uint256 txid, const CCoins &coins) { return false; } @@ -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<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 @@ bool CCoinsViewBacked::HaveCoins(uint256 txid) { return base->HaveCoins(txid); } @@ -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<uint256, CCoins> &mapCoins, CBlockIndex *pindex) { return base->BatchWrite(mapCoins, pindex); }
CCoinsViewCache::CCoinsViewCache(CCoinsView &baseIn, bool fDummy) : CCoinsViewBacked(baseIn), pindexTip(NULL) { }
@ -218,16 +213,22 @@ bool CCoinsViewCache::SetBestBlock(CBlockIndex *pindex) { @@ -218,16 +213,22 @@ bool CCoinsViewCache::SetBestBlock(CBlockIndex *pindex) {
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;
bool fOk = base->BatchWrite(cacheCoins, pindexTip);
if (fOk)
cacheCoins.clear();
pindexTip = NULL;
return true;
return fOk;
}
unsigned int CCoinsViewCache::GetCacheSize() {
return cacheCoins.size();
}
/** CCoinsView that brings transactions from a memorypool into view.
@ -249,7 +250,7 @@ bool CCoinsViewMemPool::HaveCoins(uint256 txid) { @@ -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) @@ -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) @@ -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, @@ -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, @@ -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 @@ -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()
{
CCoinsDB coinsdb("r");
return AcceptToMemoryPool(coinsdb);
}
bool CWalletTx::AcceptWalletTransaction(CCoinsDB& coinsdb, bool fCheckInputs)
bool CWalletTx::AcceptWalletTransaction(bool fCheckInputs)
{
{
LOCK(mempool.cs);
// Add previous supporting transactions first
@ -882,20 +873,15 @@ bool CWalletTx::AcceptWalletTransaction(CCoinsDB& coinsdb, bool fCheckInputs) @@ -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 @@ -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 @@ -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) @@ -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) @@ -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) @@ -1646,10 +1627,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)
@ -1657,11 +1641,10 @@ bool CBlock::SetBestChain(CBlockIndex* pindexNew) @@ -1657,11 +1641,10 @@ bool CBlock::SetBestChain(CBlockIndex* pindexNew)
}
// Make sure it's successfully written to disk before changing memory structure
bool fIsInitialDownload = IsInitialBlockDownload();
if (!fIsInitialDownload || view.GetCacheSize()>5000)
if (!view.Flush())
return error("SetBestBlock() : failed to write coin changes");
if (!coinsdb.TxnCommit())
return error("SetBestBlock() : TxnCommit failed");
coinsdb.Close();
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) @@ -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) @@ -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 (pindexNew == pindexBest)
{
@ -2169,11 +2148,9 @@ bool LoadBlockIndex(bool fAllowNew) @@ -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) @@ -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) @@ -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) @@ -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) @@ -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) @@ -2929,7 +2905,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;
@ -2937,7 +2912,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) @@ -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) @@ -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) @@ -3407,11 +3382,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());
@ -3621,9 +3595,7 @@ CBlock* CreateNewBlock(CReserveKey& reservekey) @@ -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<COrphan> vOrphan; // list memory doesn't move
@ -3811,7 +3783,7 @@ CBlock* CreateNewBlock(CReserveKey& reservekey) @@ -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");
}

30
src/main.h

@ -583,7 +583,7 @@ public: @@ -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: @@ -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: @@ -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: @@ -1676,8 +1676,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();
@ -1722,6 +1721,7 @@ public: @@ -1722,6 +1721,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 */
@ -1738,21 +1738,7 @@ public: @@ -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<uint256, CCoins> &mapCoins, CBlockIndex *pindex);
};
/** CCoinsView that adds a memory cache for transactions to another CCoinsView */
@ -1769,7 +1755,9 @@ public: @@ -1769,7 +1755,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.
@ -1785,4 +1773,6 @@ public: @@ -1785,4 +1773,6 @@ public:
bool HaveCoins(uint256 txid);
};
extern CCoinsViewCache *pcoinsTip;
#endif

5
src/qt/transactiondesc.cpp

@ -234,9 +234,6 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx) @@ -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 coindb("r"); // To fetch source txouts
CCoinsViewDB coins(coindb);
strHTML += "<br><b>" + tr("Inputs") + ":</b>";
strHTML += "<ul>";
@ -247,7 +244,7 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx) @@ -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())
{

4
src/rpcmining.cpp

@ -281,9 +281,7 @@ Value getblocktemplate(const Array& params, bool fHelp) @@ -281,9 +281,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();

17
src/rpcrawtransaction.cpp

@ -339,9 +339,8 @@ Value signrawtransaction(const Array& params, bool fHelp) @@ -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) @@ -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) @@ -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");
}
}

21
src/wallet.cpp

@ -767,7 +767,6 @@ int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate) @@ -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() @@ -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() @@ -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() @@ -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) @@ -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() @@ -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() @@ -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();
}
}
}

6
src/wallet.h

@ -659,11 +659,7 @@ public: @@ -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();
};

Loading…
Cancel
Save