]> Git Repo - VerusCoin.git/blob - src/txdb.cpp
Merge pull request #6369
[VerusCoin.git] / src / txdb.cpp
1 // Copyright (c) 2009-2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2014 The Bitcoin Core developers
3 // Distributed under the MIT software license, see the accompanying
4 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
5
6 #include "txdb.h"
7
8 #include "chainparams.h"
9 #include "hash.h"
10 #include "main.h"
11 #include "pow.h"
12 #include "uint256.h"
13
14 #include <stdint.h>
15
16 #include <boost/thread.hpp>
17
18 using namespace std;
19
20 static const char DB_COINS = 'c';
21 static const char DB_BLOCK_FILES = 'f';
22 static const char DB_TXINDEX = 't';
23 static const char DB_BLOCK_INDEX = 'b';
24
25 static const char DB_BEST_BLOCK = 'B';
26 static const char DB_FLAG = 'F';
27 static const char DB_REINDEX_FLAG = 'R';
28 static const char DB_LAST_BLOCK = 'l';
29
30
31 void static BatchWriteCoins(CLevelDBBatch &batch, const uint256 &hash, const CCoins &coins) {
32     if (coins.IsPruned())
33         batch.Erase(make_pair(DB_COINS, hash));
34     else
35         batch.Write(make_pair(DB_COINS, hash), coins);
36 }
37
38 void static BatchWriteHashBestChain(CLevelDBBatch &batch, const uint256 &hash) {
39     batch.Write(DB_BEST_BLOCK, hash);
40 }
41
42 CCoinsViewDB::CCoinsViewDB(size_t nCacheSize, bool fMemory, bool fWipe) : db(GetDataDir() / "chainstate", nCacheSize, fMemory, fWipe) {
43 }
44
45 bool CCoinsViewDB::GetCoins(const uint256 &txid, CCoins &coins) const {
46     return db.Read(make_pair(DB_COINS, txid), coins);
47 }
48
49 bool CCoinsViewDB::HaveCoins(const uint256 &txid) const {
50     return db.Exists(make_pair(DB_COINS, txid));
51 }
52
53 uint256 CCoinsViewDB::GetBestBlock() const {
54     uint256 hashBestChain;
55     if (!db.Read(DB_BEST_BLOCK, hashBestChain))
56         return uint256();
57     return hashBestChain;
58 }
59
60 bool CCoinsViewDB::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) {
61     CLevelDBBatch batch;
62     size_t count = 0;
63     size_t changed = 0;
64     for (CCoinsMap::iterator it = mapCoins.begin(); it != mapCoins.end();) {
65         if (it->second.flags & CCoinsCacheEntry::DIRTY) {
66             BatchWriteCoins(batch, it->first, it->second.coins);
67             changed++;
68         }
69         count++;
70         CCoinsMap::iterator itOld = it++;
71         mapCoins.erase(itOld);
72     }
73     if (!hashBlock.IsNull())
74         BatchWriteHashBestChain(batch, hashBlock);
75
76     LogPrint("coindb", "Committing %u changed transactions (out of %u) to coin database...\n", (unsigned int)changed, (unsigned int)count);
77     return db.WriteBatch(batch);
78 }
79
80 CBlockTreeDB::CBlockTreeDB(size_t nCacheSize, bool fMemory, bool fWipe) : CLevelDBWrapper(GetDataDir() / "blocks" / "index", nCacheSize, fMemory, fWipe) {
81 }
82
83 bool CBlockTreeDB::ReadBlockFileInfo(int nFile, CBlockFileInfo &info) {
84     return Read(make_pair(DB_BLOCK_FILES, nFile), info);
85 }
86
87 bool CBlockTreeDB::WriteReindexing(bool fReindexing) {
88     if (fReindexing)
89         return Write(DB_REINDEX_FLAG, '1');
90     else
91         return Erase(DB_REINDEX_FLAG);
92 }
93
94 bool CBlockTreeDB::ReadReindexing(bool &fReindexing) {
95     fReindexing = Exists(DB_REINDEX_FLAG);
96     return true;
97 }
98
99 bool CBlockTreeDB::ReadLastBlockFile(int &nFile) {
100     return Read(DB_LAST_BLOCK, nFile);
101 }
102
103 bool CCoinsViewDB::GetStats(CCoinsStats &stats) const {
104     /* It seems that there are no "const iterators" for LevelDB.  Since we
105        only need read operations on it, use a const-cast to get around
106        that restriction.  */
107     boost::scoped_ptr<leveldb::Iterator> pcursor(const_cast<CLevelDBWrapper*>(&db)->NewIterator());
108     pcursor->SeekToFirst();
109
110     CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION);
111     stats.hashBlock = GetBestBlock();
112     ss << stats.hashBlock;
113     CAmount nTotalAmount = 0;
114     while (pcursor->Valid()) {
115         boost::this_thread::interruption_point();
116         try {
117             leveldb::Slice slKey = pcursor->key();
118             CDataStream ssKey(slKey.data(), slKey.data()+slKey.size(), SER_DISK, CLIENT_VERSION);
119             char chType;
120             ssKey >> chType;
121             if (chType == DB_COINS) {
122                 leveldb::Slice slValue = pcursor->value();
123                 CDataStream ssValue(slValue.data(), slValue.data()+slValue.size(), SER_DISK, CLIENT_VERSION);
124                 CCoins coins;
125                 ssValue >> coins;
126                 uint256 txhash;
127                 ssKey >> txhash;
128                 ss << txhash;
129                 ss << VARINT(coins.nVersion);
130                 ss << (coins.fCoinBase ? 'c' : 'n');
131                 ss << VARINT(coins.nHeight);
132                 stats.nTransactions++;
133                 for (unsigned int i=0; i<coins.vout.size(); i++) {
134                     const CTxOut &out = coins.vout[i];
135                     if (!out.IsNull()) {
136                         stats.nTransactionOutputs++;
137                         ss << VARINT(i+1);
138                         ss << out;
139                         nTotalAmount += out.nValue;
140                     }
141                 }
142                 stats.nSerializedSize += 32 + slValue.size();
143                 ss << VARINT(0);
144             }
145             pcursor->Next();
146         } catch (const std::exception& e) {
147             return error("%s: Deserialize or I/O error - %s", __func__, e.what());
148         }
149     }
150     stats.nHeight = mapBlockIndex.find(GetBestBlock())->second->nHeight;
151     stats.hashSerialized = ss.GetHash();
152     stats.nTotalAmount = nTotalAmount;
153     return true;
154 }
155
156 bool CBlockTreeDB::WriteBatchSync(const std::vector<std::pair<int, const CBlockFileInfo*> >& fileInfo, int nLastFile, const std::vector<const CBlockIndex*>& blockinfo) {
157     CLevelDBBatch batch;
158     for (std::vector<std::pair<int, const CBlockFileInfo*> >::const_iterator it=fileInfo.begin(); it != fileInfo.end(); it++) {
159         batch.Write(make_pair(DB_BLOCK_FILES, it->first), *it->second);
160     }
161     batch.Write(DB_LAST_BLOCK, nLastFile);
162     for (std::vector<const CBlockIndex*>::const_iterator it=blockinfo.begin(); it != blockinfo.end(); it++) {
163         batch.Write(make_pair(DB_BLOCK_INDEX, (*it)->GetBlockHash()), CDiskBlockIndex(*it));
164     }
165     return WriteBatch(batch, true);
166 }
167
168 bool CBlockTreeDB::ReadTxIndex(const uint256 &txid, CDiskTxPos &pos) {
169     return Read(make_pair(DB_TXINDEX, txid), pos);
170 }
171
172 bool CBlockTreeDB::WriteTxIndex(const std::vector<std::pair<uint256, CDiskTxPos> >&vect) {
173     CLevelDBBatch batch;
174     for (std::vector<std::pair<uint256,CDiskTxPos> >::const_iterator it=vect.begin(); it!=vect.end(); it++)
175         batch.Write(make_pair(DB_TXINDEX, it->first), it->second);
176     return WriteBatch(batch);
177 }
178
179 bool CBlockTreeDB::WriteFlag(const std::string &name, bool fValue) {
180     return Write(std::make_pair(DB_FLAG, name), fValue ? '1' : '0');
181 }
182
183 bool CBlockTreeDB::ReadFlag(const std::string &name, bool &fValue) {
184     char ch;
185     if (!Read(std::make_pair(DB_FLAG, name), ch))
186         return false;
187     fValue = ch == '1';
188     return true;
189 }
190
191 bool CBlockTreeDB::LoadBlockIndexGuts()
192 {
193     boost::scoped_ptr<leveldb::Iterator> pcursor(NewIterator());
194
195     CDataStream ssKeySet(SER_DISK, CLIENT_VERSION);
196     ssKeySet << make_pair(DB_BLOCK_INDEX, uint256());
197     pcursor->Seek(ssKeySet.str());
198
199     // Load mapBlockIndex
200     while (pcursor->Valid()) {
201         boost::this_thread::interruption_point();
202         try {
203             leveldb::Slice slKey = pcursor->key();
204             CDataStream ssKey(slKey.data(), slKey.data()+slKey.size(), SER_DISK, CLIENT_VERSION);
205             char chType;
206             ssKey >> chType;
207             if (chType == DB_BLOCK_INDEX) {
208                 leveldb::Slice slValue = pcursor->value();
209                 CDataStream ssValue(slValue.data(), slValue.data()+slValue.size(), SER_DISK, CLIENT_VERSION);
210                 CDiskBlockIndex diskindex;
211                 ssValue >> diskindex;
212
213                 // Construct block index object
214                 CBlockIndex* pindexNew = InsertBlockIndex(diskindex.GetBlockHash());
215                 pindexNew->pprev          = InsertBlockIndex(diskindex.hashPrev);
216                 pindexNew->nHeight        = diskindex.nHeight;
217                 pindexNew->nFile          = diskindex.nFile;
218                 pindexNew->nDataPos       = diskindex.nDataPos;
219                 pindexNew->nUndoPos       = diskindex.nUndoPos;
220                 pindexNew->nVersion       = diskindex.nVersion;
221                 pindexNew->hashMerkleRoot = diskindex.hashMerkleRoot;
222                 pindexNew->nTime          = diskindex.nTime;
223                 pindexNew->nBits          = diskindex.nBits;
224                 pindexNew->nNonce         = diskindex.nNonce;
225                 pindexNew->nStatus        = diskindex.nStatus;
226                 pindexNew->nTx            = diskindex.nTx;
227
228                 if (!CheckProofOfWork(pindexNew->GetBlockHash(), pindexNew->nBits, Params().GetConsensus()))
229                     return error("LoadBlockIndex(): CheckProofOfWork failed: %s", pindexNew->ToString());
230
231                 pcursor->Next();
232             } else {
233                 break; // if shutdown requested or finished loading block index
234             }
235         } catch (const std::exception& e) {
236             return error("%s: Deserialize or I/O error - %s", __func__, e.what());
237         }
238     }
239
240     return true;
241 }
This page took 0.037041 seconds and 4 git commands to generate.