You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

txdb.cpp 7.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  1. // Copyright (c) 2009-2010 Satoshi Nakamoto
  2. // Copyright (c) 2009-2012 The Bitcoin developers
  3. // Distributed under the MIT/X11 software license, see the accompanying
  4. // file COPYING or http://www.opensource.org/licenses/mit-license.php.
  5. #include "txdb.h"
  6. #include "main.h"
  7. using namespace std;
  8. void static BatchWriteCoins(CLevelDBBatch &batch, const uint256 &hash, const CCoins &coins) {
  9. if (coins.IsPruned())
  10. batch.Erase(make_pair('c', hash));
  11. else
  12. batch.Write(make_pair('c', hash), coins);
  13. }
  14. void static BatchWriteHashBestChain(CLevelDBBatch &batch, const uint256 &hash) {
  15. batch.Write('B', hash);
  16. }
  17. CCoinsViewDB::CCoinsViewDB(size_t nCacheSize, bool fMemory, bool fWipe) : db(GetDataDir() / "chainstate", nCacheSize, fMemory, fWipe) {
  18. }
  19. bool CCoinsViewDB::GetCoins(uint256 txid, CCoins &coins) {
  20. return db.Read(make_pair('c', txid), coins);
  21. }
  22. bool CCoinsViewDB::SetCoins(uint256 txid, const CCoins &coins) {
  23. CLevelDBBatch batch;
  24. BatchWriteCoins(batch, txid, coins);
  25. return db.WriteBatch(batch);
  26. }
  27. bool CCoinsViewDB::HaveCoins(uint256 txid) {
  28. return db.Exists(make_pair('c', txid));
  29. }
  30. CBlockIndex *CCoinsViewDB::GetBestBlock() {
  31. uint256 hashBestChain;
  32. if (!db.Read('B', hashBestChain))
  33. return NULL;
  34. std::map<uint256, CBlockIndex*>::iterator it = mapBlockIndex.find(hashBestChain);
  35. if (it == mapBlockIndex.end())
  36. return NULL;
  37. return it->second;
  38. }
  39. bool CCoinsViewDB::SetBestBlock(CBlockIndex *pindex) {
  40. CLevelDBBatch batch;
  41. BatchWriteHashBestChain(batch, pindex->GetBlockHash());
  42. return db.WriteBatch(batch);
  43. }
  44. bool CCoinsViewDB::BatchWrite(const std::map<uint256, CCoins> &mapCoins, CBlockIndex *pindex) {
  45. printf("Committing %u changed transactions to coin database...\n", (unsigned int)mapCoins.size());
  46. CLevelDBBatch batch;
  47. for (std::map<uint256, CCoins>::const_iterator it = mapCoins.begin(); it != mapCoins.end(); it++)
  48. BatchWriteCoins(batch, it->first, it->second);
  49. if (pindex)
  50. BatchWriteHashBestChain(batch, pindex->GetBlockHash());
  51. return db.WriteBatch(batch);
  52. }
  53. CBlockTreeDB::CBlockTreeDB(size_t nCacheSize, bool fMemory, bool fWipe) : CLevelDB(GetDataDir() / "blocks" / "index", nCacheSize, fMemory, fWipe) {
  54. }
  55. bool CBlockTreeDB::WriteBlockIndex(const CDiskBlockIndex& blockindex)
  56. {
  57. return Write(make_pair('b', blockindex.GetBlockHash()), blockindex);
  58. }
  59. bool CBlockTreeDB::ReadBestInvalidWork(CBigNum& bnBestInvalidWork)
  60. {
  61. return Read('I', bnBestInvalidWork);
  62. }
  63. bool CBlockTreeDB::WriteBestInvalidWork(const CBigNum& bnBestInvalidWork)
  64. {
  65. return Write('I', bnBestInvalidWork);
  66. }
  67. bool CBlockTreeDB::WriteBlockFileInfo(int nFile, const CBlockFileInfo &info) {
  68. return Write(make_pair('f', nFile), info);
  69. }
  70. bool CBlockTreeDB::ReadBlockFileInfo(int nFile, CBlockFileInfo &info) {
  71. return Read(make_pair('f', nFile), info);
  72. }
  73. bool CBlockTreeDB::WriteLastBlockFile(int nFile) {
  74. return Write('l', nFile);
  75. }
  76. bool CBlockTreeDB::WriteReindexing(bool fReindexing) {
  77. if (fReindexing)
  78. return Write('R', '1');
  79. else
  80. return Erase('R');
  81. }
  82. bool CBlockTreeDB::ReadReindexing(bool &fReindexing) {
  83. fReindexing = Exists('R');
  84. return true;
  85. }
  86. bool CBlockTreeDB::ReadLastBlockFile(int &nFile) {
  87. return Read('l', nFile);
  88. }
  89. bool CCoinsViewDB::GetStats(CCoinsStats &stats) {
  90. leveldb::Iterator *pcursor = db.NewIterator();
  91. pcursor->SeekToFirst();
  92. while (pcursor->Valid()) {
  93. try {
  94. leveldb::Slice slKey = pcursor->key();
  95. CDataStream ssKey(slKey.data(), slKey.data()+slKey.size(), SER_DISK, CLIENT_VERSION);
  96. char chType;
  97. ssKey >> chType;
  98. if (chType == 'c' && !fRequestShutdown) {
  99. leveldb::Slice slValue = pcursor->value();
  100. CDataStream ssValue(slValue.data(), slValue.data()+slValue.size(), SER_DISK, CLIENT_VERSION);
  101. CCoins coins;
  102. ssValue >> coins;
  103. uint256 txhash;
  104. ssKey >> txhash;
  105. stats.nTransactions++;
  106. BOOST_FOREACH(const CTxOut &out, coins.vout) {
  107. if (!out.IsNull())
  108. stats.nTransactionOutputs++;
  109. }
  110. stats.nSerializedSize += 32 + slValue.size();
  111. }
  112. pcursor->Next();
  113. } catch (std::exception &e) {
  114. return error("%s() : deserialize error", __PRETTY_FUNCTION__);
  115. }
  116. }
  117. delete pcursor;
  118. stats.nHeight = GetBestBlock()->nHeight;
  119. return true;
  120. }
  121. bool CBlockTreeDB::ReadTxIndex(const uint256 &txid, CDiskTxPos &pos) {
  122. return Read(make_pair('t', txid), pos);
  123. }
  124. bool CBlockTreeDB::WriteTxIndex(const std::vector<std::pair<uint256, CDiskTxPos> >&vect) {
  125. CLevelDBBatch batch;
  126. for (std::vector<std::pair<uint256,CDiskTxPos> >::const_iterator it=vect.begin(); it!=vect.end(); it++)
  127. batch.Write(make_pair('t', it->first), it->second);
  128. return WriteBatch(batch);
  129. }
  130. bool CBlockTreeDB::WriteFlag(const std::string &name, bool fValue) {
  131. return Write(std::make_pair('F', name), fValue ? '1' : '0');
  132. }
  133. bool CBlockTreeDB::ReadFlag(const std::string &name, bool &fValue) {
  134. char ch;
  135. if (!Read(std::make_pair('F', name), ch))
  136. return false;
  137. fValue = ch == '1';
  138. return true;
  139. }
  140. bool CBlockTreeDB::LoadBlockIndexGuts()
  141. {
  142. leveldb::Iterator *pcursor = NewIterator();
  143. CDataStream ssKeySet(SER_DISK, CLIENT_VERSION);
  144. ssKeySet << make_pair('b', uint256(0));
  145. pcursor->Seek(ssKeySet.str());
  146. // Load mapBlockIndex
  147. while (pcursor->Valid()) {
  148. try {
  149. leveldb::Slice slKey = pcursor->key();
  150. CDataStream ssKey(slKey.data(), slKey.data()+slKey.size(), SER_DISK, CLIENT_VERSION);
  151. char chType;
  152. ssKey >> chType;
  153. if (chType == 'b' && !fRequestShutdown) {
  154. leveldb::Slice slValue = pcursor->value();
  155. CDataStream ssValue(slValue.data(), slValue.data()+slValue.size(), SER_DISK, CLIENT_VERSION);
  156. CDiskBlockIndex diskindex;
  157. ssValue >> diskindex;
  158. // Construct block index object
  159. CBlockIndex* pindexNew = InsertBlockIndex(diskindex.GetBlockHash());
  160. pindexNew->pprev = InsertBlockIndex(diskindex.hashPrev);
  161. pindexNew->nHeight = diskindex.nHeight;
  162. pindexNew->nFile = diskindex.nFile;
  163. pindexNew->nDataPos = diskindex.nDataPos;
  164. pindexNew->nUndoPos = diskindex.nUndoPos;
  165. pindexNew->nVersion = diskindex.nVersion;
  166. pindexNew->hashMerkleRoot = diskindex.hashMerkleRoot;
  167. pindexNew->nTime = diskindex.nTime;
  168. pindexNew->nBits = diskindex.nBits;
  169. pindexNew->nNonce = diskindex.nNonce;
  170. pindexNew->nStatus = diskindex.nStatus;
  171. pindexNew->nTx = diskindex.nTx;
  172. // Watch for genesis block
  173. if (pindexGenesisBlock == NULL && diskindex.GetBlockHash() == hashGenesisBlock)
  174. pindexGenesisBlock = pindexNew;
  175. if (!pindexNew->CheckIndex())
  176. return error("LoadBlockIndex() : CheckIndex failed: %s", pindexNew->ToString().c_str());
  177. pcursor->Next();
  178. } else {
  179. break; // if shutdown requested or finished loading block index
  180. }
  181. } catch (std::exception &e) {
  182. return error("%s() : deserialize error", __PRETTY_FUNCTION__);
  183. }
  184. }
  185. delete pcursor;
  186. return true;
  187. }