]> Git Repo - VerusCoin.git/blob - src/txdb.cpp
Merge pull request #2981 from gmaxwell/tor2onion
[VerusCoin.git] / src / txdb.cpp
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
6 #include "txdb.h"
7 #include "main.h"
8 #include "hash.h"
9 #include "chainparams.h"
10
11 using namespace std;
12
13 void static BatchWriteCoins(CLevelDBBatch &batch, const uint256 &hash, const CCoins &coins) {
14     if (coins.IsPruned())
15         batch.Erase(make_pair('c', hash));
16     else
17         batch.Write(make_pair('c', hash), coins);
18 }
19
20 void static BatchWriteHashBestChain(CLevelDBBatch &batch, const uint256 &hash) {
21     batch.Write('B', hash);
22 }
23
24 CCoinsViewDB::CCoinsViewDB(size_t nCacheSize, bool fMemory, bool fWipe) : db(GetDataDir() / "chainstate", nCacheSize, fMemory, fWipe) {
25 }
26
27 bool CCoinsViewDB::GetCoins(const uint256 &txid, CCoins &coins) { 
28     return db.Read(make_pair('c', txid), coins); 
29 }
30
31 bool CCoinsViewDB::SetCoins(const uint256 &txid, const CCoins &coins) {
32     CLevelDBBatch batch;
33     BatchWriteCoins(batch, txid, coins);
34     return db.WriteBatch(batch);
35 }
36
37 bool CCoinsViewDB::HaveCoins(const uint256 &txid) {
38     return db.Exists(make_pair('c', txid)); 
39 }
40
41 CBlockIndex *CCoinsViewDB::GetBestBlock() {
42     uint256 hashBestChain;
43     if (!db.Read('B', hashBestChain))
44         return NULL;
45     std::map<uint256, CBlockIndex*>::iterator it = mapBlockIndex.find(hashBestChain);
46     if (it == mapBlockIndex.end())
47         return NULL;
48     return it->second;
49 }
50
51 bool CCoinsViewDB::SetBestBlock(CBlockIndex *pindex) {
52     CLevelDBBatch batch;
53     BatchWriteHashBestChain(batch, pindex->GetBlockHash()); 
54     return db.WriteBatch(batch);
55 }
56
57 bool CCoinsViewDB::BatchWrite(const std::map<uint256, CCoins> &mapCoins, CBlockIndex *pindex) {
58     LogPrint("coindb", "Committing %u changed transactions to coin database...\n", (unsigned int)mapCoins.size());
59
60     CLevelDBBatch batch;
61     for (std::map<uint256, CCoins>::const_iterator it = mapCoins.begin(); it != mapCoins.end(); it++)
62         BatchWriteCoins(batch, it->first, it->second);
63     if (pindex)
64         BatchWriteHashBestChain(batch, pindex->GetBlockHash());
65
66     return db.WriteBatch(batch);
67 }
68
69 CBlockTreeDB::CBlockTreeDB(size_t nCacheSize, bool fMemory, bool fWipe) : CLevelDB(GetDataDir() / "blocks" / "index", nCacheSize, fMemory, fWipe) {
70 }
71
72 bool CBlockTreeDB::WriteBlockIndex(const CDiskBlockIndex& blockindex)
73 {
74     return Write(make_pair('b', blockindex.GetBlockHash()), blockindex);
75 }
76
77 bool CBlockTreeDB::ReadBestInvalidWork(CBigNum& bnBestInvalidWork)
78 {
79     return Read('I', bnBestInvalidWork);
80 }
81
82 bool CBlockTreeDB::WriteBestInvalidWork(const CBigNum& bnBestInvalidWork)
83 {
84     return Write('I', bnBestInvalidWork);
85 }
86
87 bool CBlockTreeDB::WriteBlockFileInfo(int nFile, const CBlockFileInfo &info) {
88     return Write(make_pair('f', nFile), info);
89 }
90
91 bool CBlockTreeDB::ReadBlockFileInfo(int nFile, CBlockFileInfo &info) {
92     return Read(make_pair('f', nFile), info);
93 }
94
95 bool CBlockTreeDB::WriteLastBlockFile(int nFile) {
96     return Write('l', nFile);
97 }
98
99 bool CBlockTreeDB::WriteReindexing(bool fReindexing) {
100     if (fReindexing)
101         return Write('R', '1');
102     else
103         return Erase('R');
104 }
105
106 bool CBlockTreeDB::ReadReindexing(bool &fReindexing) {
107     fReindexing = Exists('R');
108     return true;
109 }
110
111 bool CBlockTreeDB::ReadLastBlockFile(int &nFile) {
112     return Read('l', nFile);
113 }
114
115 bool CCoinsViewDB::GetStats(CCoinsStats &stats) {
116     leveldb::Iterator *pcursor = db.NewIterator();
117     pcursor->SeekToFirst();
118
119     CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION);
120     stats.hashBlock = GetBestBlock()->GetBlockHash();
121     ss << stats.hashBlock;
122     int64 nTotalAmount = 0;
123     while (pcursor->Valid()) {
124         boost::this_thread::interruption_point();
125         try {
126             leveldb::Slice slKey = pcursor->key();
127             CDataStream ssKey(slKey.data(), slKey.data()+slKey.size(), SER_DISK, CLIENT_VERSION);
128             char chType;
129             ssKey >> chType;
130             if (chType == 'c') {
131                 leveldb::Slice slValue = pcursor->value();
132                 CDataStream ssValue(slValue.data(), slValue.data()+slValue.size(), SER_DISK, CLIENT_VERSION);
133                 CCoins coins;
134                 ssValue >> coins;
135                 uint256 txhash;
136                 ssKey >> txhash;
137                 ss << txhash;
138                 ss << VARINT(coins.nVersion);
139                 ss << (coins.fCoinBase ? 'c' : 'n'); 
140                 ss << VARINT(coins.nHeight);
141                 stats.nTransactions++;
142                 for (unsigned int i=0; i<coins.vout.size(); i++) {
143                     const CTxOut &out = coins.vout[i];
144                     if (!out.IsNull()) {
145                         stats.nTransactionOutputs++;
146                         ss << VARINT(i+1);
147                         ss << out;
148                         nTotalAmount += out.nValue;
149                     }
150                 }
151                 stats.nSerializedSize += 32 + slValue.size();
152                 ss << VARINT(0);
153             }
154             pcursor->Next();
155         } catch (std::exception &e) {
156             return error("%s() : deserialize error", __PRETTY_FUNCTION__);
157         }
158     }
159     delete pcursor;
160     stats.nHeight = GetBestBlock()->nHeight;
161     stats.hashSerialized = ss.GetHash();
162     stats.nTotalAmount = nTotalAmount;
163     return true;
164 }
165
166 bool CBlockTreeDB::ReadTxIndex(const uint256 &txid, CDiskTxPos &pos) {
167     return Read(make_pair('t', txid), pos);
168 }
169
170 bool CBlockTreeDB::WriteTxIndex(const std::vector<std::pair<uint256, CDiskTxPos> >&vect) {
171     CLevelDBBatch batch;
172     for (std::vector<std::pair<uint256,CDiskTxPos> >::const_iterator it=vect.begin(); it!=vect.end(); it++)
173         batch.Write(make_pair('t', it->first), it->second);
174     return WriteBatch(batch);
175 }
176
177 bool CBlockTreeDB::WriteFlag(const std::string &name, bool fValue) {
178     return Write(std::make_pair('F', name), fValue ? '1' : '0');
179 }
180
181 bool CBlockTreeDB::ReadFlag(const std::string &name, bool &fValue) {
182     char ch;
183     if (!Read(std::make_pair('F', name), ch))
184         return false;
185     fValue = ch == '1';
186     return true;
187 }
188
189 bool CBlockTreeDB::LoadBlockIndexGuts()
190 {
191     leveldb::Iterator *pcursor = NewIterator();
192
193     CDataStream ssKeySet(SER_DISK, CLIENT_VERSION);
194     ssKeySet << make_pair('b', uint256(0));
195     pcursor->Seek(ssKeySet.str());
196
197     // Load mapBlockIndex
198     while (pcursor->Valid()) {
199         boost::this_thread::interruption_point();
200         try {
201             leveldb::Slice slKey = pcursor->key();
202             CDataStream ssKey(slKey.data(), slKey.data()+slKey.size(), SER_DISK, CLIENT_VERSION);
203             char chType;
204             ssKey >> chType;
205             if (chType == 'b') {
206                 leveldb::Slice slValue = pcursor->value();
207                 CDataStream ssValue(slValue.data(), slValue.data()+slValue.size(), SER_DISK, CLIENT_VERSION);
208                 CDiskBlockIndex diskindex;
209                 ssValue >> diskindex;
210
211                 // Construct block index object
212                 CBlockIndex* pindexNew = InsertBlockIndex(diskindex.GetBlockHash());
213                 pindexNew->pprev          = InsertBlockIndex(diskindex.hashPrev);
214                 pindexNew->nHeight        = diskindex.nHeight;
215                 pindexNew->nFile          = diskindex.nFile;
216                 pindexNew->nDataPos       = diskindex.nDataPos;
217                 pindexNew->nUndoPos       = diskindex.nUndoPos;
218                 pindexNew->nVersion       = diskindex.nVersion;
219                 pindexNew->hashMerkleRoot = diskindex.hashMerkleRoot;
220                 pindexNew->nTime          = diskindex.nTime;
221                 pindexNew->nBits          = diskindex.nBits;
222                 pindexNew->nNonce         = diskindex.nNonce;
223                 pindexNew->nStatus        = diskindex.nStatus;
224                 pindexNew->nTx            = diskindex.nTx;
225
226                 if (!pindexNew->CheckIndex())
227                     return error("LoadBlockIndex() : CheckIndex failed: %s", pindexNew->ToString().c_str());
228
229                 pcursor->Next();
230             } else {
231                 break; // if shutdown requested or finished loading block index
232             }
233         } catch (std::exception &e) {
234             return error("%s() : deserialize error", __PRETTY_FUNCTION__);
235         }
236     }
237     delete pcursor;
238
239     return true;
240 }
This page took 0.036726 seconds and 4 git commands to generate.