Back to home page

Bitcoin sources

 
 

    


File indexing completed on 2020-06-26 05:01:46

0001 // Copyright (c) 2009-2010 Satoshi Nakamoto
0002 // Copyright (c) 2009-2014 The Bitcoin developers
0003 // Distributed under the MIT/X11 software license, see the accompanying
0004 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
0005 
0006 #include "txdb.h"
0007 
0008 #include "pow.h"
0009 #include "uint256.h"
0010 
0011 #include <stdint.h>
0012 
0013 #include <boost/thread.hpp>
0014 
0015 using namespace std;
0016 
0017 void static BatchWriteCoins(CLevelDBBatch &batch, const uint256 &hash, const CCoins &coins) {
0018     if (coins.IsPruned())
0019         batch.Erase(make_pair('c', hash));
0020     else
0021         batch.Write(make_pair('c', hash), coins);
0022 }
0023 
0024 void static BatchWriteHashBestChain(CLevelDBBatch &batch, const uint256 &hash) {
0025     batch.Write('B', hash);
0026 }
0027 
0028 CCoinsViewDB::CCoinsViewDB(size_t nCacheSize, bool fMemory, bool fWipe) : db(GetDataDir() / "chainstate", nCacheSize, fMemory, fWipe) {
0029 }
0030 
0031 bool CCoinsViewDB::GetCoins(const uint256 &txid, CCoins &coins) const {
0032     return db.Read(make_pair('c', txid), coins);
0033 }
0034 
0035 bool CCoinsViewDB::HaveCoins(const uint256 &txid) const {
0036     return db.Exists(make_pair('c', txid));
0037 }
0038 
0039 uint256 CCoinsViewDB::GetBestBlock() const {
0040     uint256 hashBestChain;
0041     if (!db.Read('B', hashBestChain))
0042         return uint256(0);
0043     return hashBestChain;
0044 }
0045 
0046 bool CCoinsViewDB::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) {
0047     CLevelDBBatch batch;
0048     size_t count = 0;
0049     size_t changed = 0;
0050     for (CCoinsMap::iterator it = mapCoins.begin(); it != mapCoins.end();) {
0051         if (it->second.flags & CCoinsCacheEntry::DIRTY) {
0052             BatchWriteCoins(batch, it->first, it->second.coins);
0053             changed++;
0054         }
0055         count++;
0056         CCoinsMap::iterator itOld = it++;
0057         mapCoins.erase(itOld);
0058     }
0059     if (hashBlock != uint256(0))
0060         BatchWriteHashBestChain(batch, hashBlock);
0061 
0062     LogPrint("coindb", "Committing %u changed transactions (out of %u) to coin database...\n", (unsigned int)changed, (unsigned int)count);
0063     return db.WriteBatch(batch);
0064 }
0065 
0066 CBlockTreeDB::CBlockTreeDB(size_t nCacheSize, bool fMemory, bool fWipe) : CLevelDBWrapper(GetDataDir() / "blocks" / "index", nCacheSize, fMemory, fWipe) {
0067 }
0068 
0069 bool CBlockTreeDB::WriteBlockIndex(const CDiskBlockIndex& blockindex)
0070 {
0071     return Write(make_pair('b', blockindex.GetBlockHash()), blockindex);
0072 }
0073 
0074 bool CBlockTreeDB::WriteBlockFileInfo(int nFile, const CBlockFileInfo &info) {
0075     return Write(make_pair('f', nFile), info);
0076 }
0077 
0078 bool CBlockTreeDB::ReadBlockFileInfo(int nFile, CBlockFileInfo &info) {
0079     return Read(make_pair('f', nFile), info);
0080 }
0081 
0082 bool CBlockTreeDB::WriteLastBlockFile(int nFile) {
0083     return Write('l', nFile);
0084 }
0085 
0086 bool CBlockTreeDB::WriteReindexing(bool fReindexing) {
0087     if (fReindexing)
0088         return Write('R', '1');
0089     else
0090         return Erase('R');
0091 }
0092 
0093 bool CBlockTreeDB::ReadReindexing(bool &fReindexing) {
0094     fReindexing = Exists('R');
0095     return true;
0096 }
0097 
0098 bool CBlockTreeDB::ReadLastBlockFile(int &nFile) {
0099     return Read('l', nFile);
0100 }
0101 
0102 bool CCoinsViewDB::GetStats(CCoinsStats &stats) const {
0103     /* It seems that there are no "const iterators" for LevelDB.  Since we
0104        only need read operations on it, use a const-cast to get around
0105        that restriction.  */
0106     boost::scoped_ptr<leveldb::Iterator> pcursor(const_cast<CLevelDBWrapper*>(&db)->NewIterator());
0107     pcursor->SeekToFirst();
0108 
0109     CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION);
0110     stats.hashBlock = GetBestBlock();
0111     ss << stats.hashBlock;
0112     CAmount nTotalAmount = 0;
0113     while (pcursor->Valid()) {
0114         boost::this_thread::interruption_point();
0115         try {
0116             leveldb::Slice slKey = pcursor->key();
0117             CDataStream ssKey(slKey.data(), slKey.data()+slKey.size(), SER_DISK, CLIENT_VERSION);
0118             char chType;
0119             ssKey >> chType;
0120             if (chType == 'c') {
0121                 leveldb::Slice slValue = pcursor->value();
0122                 CDataStream ssValue(slValue.data(), slValue.data()+slValue.size(), SER_DISK, CLIENT_VERSION);
0123                 CCoins coins;
0124                 ssValue >> coins;
0125                 uint256 txhash;
0126                 ssKey >> txhash;
0127                 ss << txhash;
0128                 ss << VARINT(coins.nVersion);
0129                 ss << (coins.fCoinBase ? 'c' : 'n');
0130                 ss << VARINT(coins.nHeight);
0131                 stats.nTransactions++;
0132                 for (unsigned int i=0; i<coins.vout.size(); i++) {
0133                     const CTxOut &out = coins.vout[i];
0134                     if (!out.IsNull()) {
0135                         stats.nTransactionOutputs++;
0136                         ss << VARINT(i+1);
0137                         ss << out;
0138                         nTotalAmount += out.nValue;
0139                     }
0140                 }
0141                 stats.nSerializedSize += 32 + slValue.size();
0142                 ss << VARINT(0);
0143             }
0144             pcursor->Next();
0145         } catch (std::exception &e) {
0146             return error("%s : Deserialize or I/O error - %s", __func__, e.what());
0147         }
0148     }
0149     stats.nHeight = mapBlockIndex.find(GetBestBlock())->second->nHeight;
0150     stats.hashSerialized = ss.GetHash();
0151     stats.nTotalAmount = nTotalAmount;
0152     return true;
0153 }
0154 
0155 bool CBlockTreeDB::ReadTxIndex(const uint256 &txid, CDiskTxPos &pos) {
0156     return Read(make_pair('t', txid), pos);
0157 }
0158 
0159 bool CBlockTreeDB::WriteTxIndex(const std::vector<std::pair<uint256, CDiskTxPos> >&vect) {
0160     CLevelDBBatch batch;
0161     for (std::vector<std::pair<uint256,CDiskTxPos> >::const_iterator it=vect.begin(); it!=vect.end(); it++)
0162         batch.Write(make_pair('t', it->first), it->second);
0163     return WriteBatch(batch);
0164 }
0165 
0166 bool CBlockTreeDB::WriteFlag(const std::string &name, bool fValue) {
0167     return Write(std::make_pair('F', name), fValue ? '1' : '0');
0168 }
0169 
0170 bool CBlockTreeDB::ReadFlag(const std::string &name, bool &fValue) {
0171     char ch;
0172     if (!Read(std::make_pair('F', name), ch))
0173         return false;
0174     fValue = ch == '1';
0175     return true;
0176 }
0177 
0178 bool CBlockTreeDB::LoadBlockIndexGuts()
0179 {
0180     boost::scoped_ptr<leveldb::Iterator> pcursor(NewIterator());
0181 
0182     CDataStream ssKeySet(SER_DISK, CLIENT_VERSION);
0183     ssKeySet << make_pair('b', uint256(0));
0184     pcursor->Seek(ssKeySet.str());
0185 
0186     // Load mapBlockIndex
0187     while (pcursor->Valid()) {
0188         boost::this_thread::interruption_point();
0189         try {
0190             leveldb::Slice slKey = pcursor->key();
0191             CDataStream ssKey(slKey.data(), slKey.data()+slKey.size(), SER_DISK, CLIENT_VERSION);
0192             char chType;
0193             ssKey >> chType;
0194             if (chType == 'b') {
0195                 leveldb::Slice slValue = pcursor->value();
0196                 CDataStream ssValue(slValue.data(), slValue.data()+slValue.size(), SER_DISK, CLIENT_VERSION);
0197                 CDiskBlockIndex diskindex;
0198                 ssValue >> diskindex;
0199 
0200                 // Construct block index object
0201                 CBlockIndex* pindexNew = InsertBlockIndex(diskindex.GetBlockHash());
0202                 pindexNew->pprev          = InsertBlockIndex(diskindex.hashPrev);
0203                 pindexNew->nHeight        = diskindex.nHeight;
0204                 pindexNew->nFile          = diskindex.nFile;
0205                 pindexNew->nDataPos       = diskindex.nDataPos;
0206                 pindexNew->nUndoPos       = diskindex.nUndoPos;
0207                 pindexNew->nVersion       = diskindex.nVersion;
0208                 pindexNew->hashMerkleRoot = diskindex.hashMerkleRoot;
0209                 pindexNew->nTime          = diskindex.nTime;
0210                 pindexNew->nBits          = diskindex.nBits;
0211                 pindexNew->nNonce         = diskindex.nNonce;
0212                 pindexNew->nStatus        = diskindex.nStatus;
0213                 pindexNew->nTx            = diskindex.nTx;
0214 
0215                 if (!CheckProofOfWork(pindexNew->GetBlockHash(), pindexNew->nBits))
0216                     return error("LoadBlockIndex() : CheckProofOfWork failed: %s", pindexNew->ToString());
0217 
0218                 pcursor->Next();
0219             } else {
0220                 break; // if shutdown requested or finished loading block index
0221             }
0222         } catch (std::exception &e) {
0223             return error("%s : Deserialize or I/O error - %s", __func__, e.what());
0224         }
0225     }
0226 
0227     return true;
0228 }