aboutsummaryrefslogtreecommitdiff
path: root/src/db.cpp
diff options
context:
space:
mode:
authorPieter Wuille <pieter.wuille@gmail.com>2012-09-03 21:14:03 +0200
committerPieter Wuille <pieter.wuille@gmail.com>2012-10-20 23:08:57 +0200
commit2d8a48292b0da96cda8d7b45a24a22adfb4667b2 (patch)
tree351935f27dcd037d68d514c3a79ff5d2d24da367 /src/db.cpp
parent44d40f26dcc73469bfbfda5f981c2c528d592ac7 (diff)
LevelDB block and coin databases
Split off CBlockTreeDB and CCoinsViewDB into txdb-*.{cpp,h} files, implemented by either LevelDB or BDB. Based on code from earlier commits by Mike Hearn in his leveldb branch.
Diffstat (limited to 'src/db.cpp')
-rw-r--r--src/db.cpp279
1 files changed, 0 insertions, 279 deletions
diff --git a/src/db.cpp b/src/db.cpp
index 5fe7e0585f..8738a0af8e 100644
--- a/src/db.cpp
+++ b/src/db.cpp
@@ -482,285 +482,6 @@ void CDBEnv::Flush(bool fShutdown)
-//
-// CBlockTreeDB and CCoinsDB
-//
-
-bool CCoinsDB::HaveCoins(uint256 hash) {
- assert(!fClient);
- return Exists(make_pair('c', hash));
-}
-
-bool CCoinsDB::ReadCoins(uint256 hash, CCoins &coins) {
- assert(!fClient);
- return Read(make_pair('c', hash), coins);
-}
-
-bool CCoinsDB::WriteCoins(uint256 hash, const CCoins &coins) {
- assert(!fClient);
- if (coins.IsPruned())
- return Erase(make_pair('c', hash));
- else
- return Write(make_pair('c', hash), coins);
-}
-
-bool CBlockTreeDB::WriteBlockIndex(const CDiskBlockIndex& blockindex)
-{
- return Write(make_pair('b', blockindex.GetBlockHash()), blockindex);
-}
-
-bool CCoinsDB::ReadHashBestChain(uint256& hashBestChain)
-{
- return Read('B', hashBestChain);
-}
-
-bool CCoinsDB::WriteHashBestChain(uint256 hashBestChain)
-{
- return Write('B', hashBestChain);
-}
-
-bool CBlockTreeDB::ReadBestInvalidWork(CBigNum& bnBestInvalidWork)
-{
- return Read('I', bnBestInvalidWork);
-}
-
-bool CBlockTreeDB::WriteBestInvalidWork(CBigNum bnBestInvalidWork)
-{
- return Write('I', bnBestInvalidWork);
-}
-
-bool CBlockTreeDB::WriteBlockFileInfo(int nFile, const CBlockFileInfo &info) {
- return Write(make_pair('f', nFile), info);
-}
-
-bool CBlockTreeDB::ReadBlockFileInfo(int nFile, CBlockFileInfo &info) {
- return Read(make_pair('f', nFile), info);
-}
-
-bool CBlockTreeDB::WriteLastBlockFile(int nFile) {
- return Write('l', nFile);
-}
-
-bool CBlockTreeDB::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)
- return NULL;
-
- // Return existing
- map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hash);
- if (mi != mapBlockIndex.end())
- return (*mi).second;
-
- // Create new
- CBlockIndex* pindexNew = new CBlockIndex();
- if (!pindexNew)
- throw runtime_error("LoadBlockIndex() : new CBlockIndex failed");
- mi = mapBlockIndex.insert(make_pair(hash, pindexNew)).first;
- pindexNew->phashBlock = &((*mi).first);
-
- return pindexNew;
-}
-
-bool LoadBlockIndexDB()
-{
- if (!pblocktree->LoadBlockIndexGuts())
- return false;
-
- if (fRequestShutdown)
- return true;
-
- // Calculate bnChainWork
- vector<pair<int, CBlockIndex*> > vSortedByHeight;
- vSortedByHeight.reserve(mapBlockIndex.size());
- BOOST_FOREACH(const PAIRTYPE(uint256, CBlockIndex*)& item, mapBlockIndex)
- {
- CBlockIndex* pindex = item.second;
- vSortedByHeight.push_back(make_pair(pindex->nHeight, pindex));
- }
- sort(vSortedByHeight.begin(), vSortedByHeight.end());
- BOOST_FOREACH(const PAIRTYPE(int, CBlockIndex*)& item, vSortedByHeight)
- {
- CBlockIndex* pindex = item.second;
- pindex->bnChainWork = (pindex->pprev ? pindex->pprev->bnChainWork : 0) + pindex->GetBlockWork();
- pindex->nChainTx = (pindex->pprev ? pindex->pprev->nChainTx : 0) + pindex->nTx;
- if ((pindex->nStatus & BLOCK_VALID_MASK) >= BLOCK_VALID_TRANSACTIONS && !(pindex->nStatus & BLOCK_FAILED_MASK))
- setBlockIndexValid.insert(pindex);
- }
-
- // Load block file info
- pblocktree->ReadLastBlockFile(nLastBlockFile);
- printf("LoadBlockIndex(): last block file = %i\n", nLastBlockFile);
- if (pblocktree->ReadBlockFileInfo(nLastBlockFile, infoLastBlockFile))
- printf("LoadBlockIndex(): last block file: %s\n", infoLastBlockFile.ToString().c_str());
-
- // Load hashBestChain pointer to end of best chain
- pindexBest = pcoinsTip->GetBestBlock();
- if (pindexBest == NULL)
- {
- if (pindexGenesisBlock == NULL)
- return true;
- }
- 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,
- DateTimeStrFormat("%x %H:%M:%S", pindexBest->GetBlockTime()).c_str());
-
- // Load bnBestInvalidWork, OK if it doesn't exist
- pblocktree->ReadBestInvalidWork(bnBestInvalidWork);
-
- // Verify blocks in the best chain
- int nCheckLevel = GetArg("-checklevel", 1);
- int nCheckDepth = GetArg( "-checkblocks", 2500);
- if (nCheckDepth == 0)
- nCheckDepth = 1000000000; // suffices until the year 19000
- if (nCheckDepth > nBestHeight)
- nCheckDepth = nBestHeight;
- printf("Verifying last %i blocks at level %i\n", nCheckDepth, nCheckLevel);
- CBlockIndex* pindexFork = NULL;
- for (CBlockIndex* pindex = pindexBest; pindex && pindex->pprev; pindex = pindex->pprev)
- {
- if (fRequestShutdown || pindex->nHeight < nBestHeight-nCheckDepth)
- break;
- CBlock block;
- if (!block.ReadFromDisk(pindex))
- return error("LoadBlockIndex() : block.ReadFromDisk failed");
- // check level 1: verify block validity
- if (nCheckLevel>0 && !block.CheckBlock())
- {
- printf("LoadBlockIndex() : *** found bad block at %d, hash=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString().c_str());
- pindexFork = pindex->pprev;
- }
- // TODO: stronger verifications
- }
- if (pindexFork && !fRequestShutdown)
- {
- // TODO: reorg back
- return error("LoadBlockIndex(): chain database corrupted");
- }
-
- return true;
-}
-
-
-
-bool CBlockTreeDB::LoadBlockIndexGuts()
-{
- // Get database cursor
- Dbc* pcursor = GetCursor();
- if (!pcursor)
- return false;
-
- // Load mapBlockIndex
- unsigned int fFlags = DB_SET_RANGE;
- loop
- {
- // Read next record
- CDataStream ssKey(SER_DISK, CLIENT_VERSION);
- if (fFlags == DB_SET_RANGE)
- ssKey << make_pair('b', uint256(0));
- CDataStream ssValue(SER_DISK, CLIENT_VERSION);
- int ret = ReadAtCursor(pcursor, ssKey, ssValue, fFlags);
- fFlags = DB_NEXT;
- if (ret == DB_NOTFOUND)
- break;
- else if (ret != 0)
- return false;
-
- // Unserialize
-
- try {
- char chType;
- ssKey >> chType;
- if (chType == 'b' && !fRequestShutdown)
- {
- CDiskBlockIndex diskindex;
- ssValue >> diskindex;
-
- // Construct block index object
- CBlockIndex* pindexNew = InsertBlockIndex(diskindex.GetBlockHash());
- pindexNew->pprev = InsertBlockIndex(diskindex.hashPrev);
- pindexNew->nHeight = diskindex.nHeight;
- pindexNew->nFile = diskindex.nFile;
- pindexNew->nDataPos = diskindex.nDataPos;
- pindexNew->nUndoPos = diskindex.nUndoPos;
- pindexNew->nVersion = diskindex.nVersion;
- pindexNew->hashMerkleRoot = diskindex.hashMerkleRoot;
- pindexNew->nTime = diskindex.nTime;
- pindexNew->nBits = diskindex.nBits;
- pindexNew->nNonce = diskindex.nNonce;
- pindexNew->nStatus = diskindex.nStatus;
- pindexNew->nTx = diskindex.nTx;
-
- // Watch for genesis block
- if (pindexGenesisBlock == NULL && diskindex.GetBlockHash() == hashGenesisBlock)
- pindexGenesisBlock = pindexNew;
-
- if (!pindexNew->CheckIndex())
- return error("LoadBlockIndex() : CheckIndex failed: %s", pindexNew->ToString().c_str());
- }
- else
- {
- break; // if shutdown requested or finished loading block index
- }
- } // try
- catch (std::exception &e) {
- return error("%s() : deserialize error", __PRETTY_FUNCTION__);
- }
- }
- pcursor->close();
-
- return true;
-}