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 8.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. // Copyright (c) 2009-2010 Satoshi Nakamoto
  2. // Copyright (c) 2009-2014 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 "core.h"
  7. #include "pow.h"
  8. #include "uint256.h"
  9. #include <stdint.h>
  10. using namespace std;
  11. void static BatchWriteCoins(CLevelDBBatch &batch, const uint256 &hash, const CCoins &coins) {
  12. if (coins.IsPruned())
  13. batch.Erase(make_pair('c', hash));
  14. else
  15. batch.Write(make_pair('c', hash), coins);
  16. }
  17. void static BatchWriteHashBestChain(CLevelDBBatch &batch, const uint256 &hash) {
  18. batch.Write('B', hash);
  19. }
  20. CCoinsViewDB::CCoinsViewDB(size_t nCacheSize, bool fMemory, bool fWipe) : db(GetDataDir() / "chainstate", nCacheSize, fMemory, fWipe) {
  21. }
  22. bool CCoinsViewDB::GetCoins(const uint256 &txid, CCoins &coins) const {
  23. return db.Read(make_pair('c', txid), coins);
  24. }
  25. bool CCoinsViewDB::SetCoins(const uint256 &txid, const CCoins &coins) {
  26. CLevelDBBatch batch;
  27. BatchWriteCoins(batch, txid, coins);
  28. return db.WriteBatch(batch);
  29. }
  30. bool CCoinsViewDB::HaveCoins(const uint256 &txid) const {
  31. return db.Exists(make_pair('c', txid));
  32. }
  33. uint256 CCoinsViewDB::GetBestBlock() const {
  34. uint256 hashBestChain;
  35. if (!db.Read('B', hashBestChain))
  36. return uint256(0);
  37. return hashBestChain;
  38. }
  39. bool CCoinsViewDB::SetBestBlock(const uint256 &hashBlock) {
  40. CLevelDBBatch batch;
  41. BatchWriteHashBestChain(batch, hashBlock);
  42. return db.WriteBatch(batch);
  43. }
  44. bool CCoinsViewDB::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) {
  45. LogPrint("coindb", "Committing %u changed transactions to coin database...\n", (unsigned int)mapCoins.size());
  46. CLevelDBBatch batch;
  47. for (CCoinsMap::iterator it = mapCoins.begin(); it != mapCoins.end();) {
  48. BatchWriteCoins(batch, it->first, it->second);
  49. CCoinsMap::iterator itOld = it++;
  50. mapCoins.erase(itOld);
  51. }
  52. if (hashBlock != uint256(0))
  53. BatchWriteHashBestChain(batch, hashBlock);
  54. return db.WriteBatch(batch);
  55. }
  56. CBlockTreeDB::CBlockTreeDB(size_t nCacheSize, bool fMemory, bool fWipe) : CLevelDBWrapper(GetDataDir() / "blocks" / "index", nCacheSize, fMemory, fWipe) {
  57. }
  58. bool CBlockTreeDB::WriteBlockIndex(const CDiskBlockIndex& blockindex)
  59. {
  60. return Write(make_pair('b', blockindex.GetBlockHash()), blockindex);
  61. }
  62. bool CBlockTreeDB::WriteBlockFileInfo(int nFile, const CBlockFileInfo &info) {
  63. return Write(make_pair('f', nFile), info);
  64. }
  65. bool CBlockTreeDB::ReadBlockFileInfo(int nFile, CBlockFileInfo &info) {
  66. return Read(make_pair('f', nFile), info);
  67. }
  68. bool CBlockTreeDB::WriteLastBlockFile(int nFile) {
  69. return Write('l', nFile);
  70. }
  71. bool CBlockTreeDB::WriteReindexing(bool fReindexing) {
  72. if (fReindexing)
  73. return Write('R', '1');
  74. else
  75. return Erase('R');
  76. }
  77. bool CBlockTreeDB::ReadReindexing(bool &fReindexing) {
  78. fReindexing = Exists('R');
  79. return true;
  80. }
  81. bool CBlockTreeDB::ReadLastBlockFile(int &nFile) {
  82. return Read('l', nFile);
  83. }
  84. bool CCoinsViewDB::GetStats(CCoinsStats &stats) const {
  85. /* It seems that there are no "const iterators" for LevelDB. Since we
  86. only need read operations on it, use a const-cast to get around
  87. that restriction. */
  88. leveldb::Iterator *pcursor = const_cast<CLevelDBWrapper*>(&db)->NewIterator();
  89. pcursor->SeekToFirst();
  90. CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION);
  91. stats.hashBlock = GetBestBlock();
  92. ss << stats.hashBlock;
  93. int64_t nTotalAmount = 0;
  94. while (pcursor->Valid()) {
  95. boost::this_thread::interruption_point();
  96. try {
  97. leveldb::Slice slKey = pcursor->key();
  98. CDataStream ssKey(slKey.data(), slKey.data()+slKey.size(), SER_DISK, CLIENT_VERSION);
  99. char chType;
  100. ssKey >> chType;
  101. if (chType == 'c') {
  102. leveldb::Slice slValue = pcursor->value();
  103. CDataStream ssValue(slValue.data(), slValue.data()+slValue.size(), SER_DISK, CLIENT_VERSION);
  104. CCoins coins;
  105. ssValue >> coins;
  106. uint256 txhash;
  107. ssKey >> txhash;
  108. ss << txhash;
  109. ss << VARINT(coins.nVersion);
  110. ss << (coins.fCoinBase ? 'c' : 'n');
  111. ss << VARINT(coins.nHeight);
  112. stats.nTransactions++;
  113. for (unsigned int i=0; i<coins.vout.size(); i++) {
  114. const CTxOut &out = coins.vout[i];
  115. if (!out.IsNull()) {
  116. stats.nTransactionOutputs++;
  117. ss << VARINT(i+1);
  118. ss << out;
  119. nTotalAmount += out.nValue;
  120. }
  121. }
  122. stats.nSerializedSize += 32 + slValue.size();
  123. ss << VARINT(0);
  124. }
  125. pcursor->Next();
  126. } catch (std::exception &e) {
  127. return error("%s : Deserialize or I/O error - %s", __func__, e.what());
  128. }
  129. }
  130. stats.nHeight = mapBlockIndex.find(GetBestBlock())->second->nHeight;
  131. stats.hashSerialized = ss.GetHash();
  132. stats.nTotalAmount = nTotalAmount;
  133. return true;
  134. }
  135. bool CBlockTreeDB::ReadTxIndex(const uint256 &txid, CDiskTxPos &pos) {
  136. return Read(make_pair('t', txid), pos);
  137. }
  138. bool CBlockTreeDB::WriteTxIndex(const std::vector<std::pair<uint256, CDiskTxPos> >&vect) {
  139. CLevelDBBatch batch;
  140. for (std::vector<std::pair<uint256,CDiskTxPos> >::const_iterator it=vect.begin(); it!=vect.end(); it++)
  141. batch.Write(make_pair('t', it->first), it->second);
  142. return WriteBatch(batch);
  143. }
  144. bool CBlockTreeDB::WriteFlag(const std::string &name, bool fValue) {
  145. return Write(std::make_pair('F', name), fValue ? '1' : '0');
  146. }
  147. bool CBlockTreeDB::ReadFlag(const std::string &name, bool &fValue) {
  148. char ch;
  149. if (!Read(std::make_pair('F', name), ch))
  150. return false;
  151. fValue = ch == '1';
  152. return true;
  153. }
  154. bool CBlockTreeDB::LoadBlockIndexGuts()
  155. {
  156. boost::scoped_ptr<leveldb::Iterator> pcursor(NewIterator());
  157. CDataStream ssKeySet(SER_DISK, CLIENT_VERSION);
  158. ssKeySet << make_pair('b', uint256(0));
  159. pcursor->Seek(ssKeySet.str());
  160. // Load mapBlockIndex
  161. while (pcursor->Valid()) {
  162. boost::this_thread::interruption_point();
  163. try {
  164. leveldb::Slice slKey = pcursor->key();
  165. CDataStream ssKey(slKey.data(), slKey.data()+slKey.size(), SER_DISK, CLIENT_VERSION);
  166. char chType;
  167. ssKey >> chType;
  168. if (chType == 'b') {
  169. leveldb::Slice slValue = pcursor->value();
  170. CDataStream ssValue(slValue.data(), slValue.data()+slValue.size(), SER_DISK, CLIENT_VERSION);
  171. CDiskBlockIndex diskindex;
  172. ssValue >> diskindex;
  173. // Construct block index object
  174. CBlockIndex* pindexNew = InsertBlockIndex(diskindex.GetBlockHash());
  175. pindexNew->pprev = InsertBlockIndex(diskindex.hashPrev);
  176. pindexNew->nHeight = diskindex.nHeight;
  177. pindexNew->nFile = diskindex.nFile;
  178. pindexNew->nDataPos = diskindex.nDataPos;
  179. pindexNew->nUndoPos = diskindex.nUndoPos;
  180. pindexNew->nVersion = diskindex.nVersion;
  181. pindexNew->hashMerkleRoot = diskindex.hashMerkleRoot;
  182. pindexNew->nTime = diskindex.nTime;
  183. pindexNew->nBits = diskindex.nBits;
  184. pindexNew->nNonce = diskindex.nNonce;
  185. pindexNew->nStatus = diskindex.nStatus;
  186. pindexNew->nTx = diskindex.nTx;
  187. if (!CheckProofOfWork(pindexNew->GetBlockHash(), pindexNew->nBits))
  188. return error("LoadBlockIndex() : CheckProofOfWork failed: %s", pindexNew->ToString());
  189. pcursor->Next();
  190. } else {
  191. break; // if shutdown requested or finished loading block index
  192. }
  193. } catch (std::exception &e) {
  194. return error("%s : Deserialize or I/O error - %s", __func__, e.what());
  195. }
  196. }
  197. return true;
  198. }