ff40b6c49ab8360b0848bcfa691f62a4a2ccc2d9
[novacoin.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
9 using namespace std;
10
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
18 void static BatchWriteHashBestChain(CLevelDBBatch &batch, const uint256 &hash) {
19     batch.Write('B', hash);
20 }
21
22 CCoinsViewDB::CCoinsViewDB(bool fMemory) : db(GetDataDir() / "coins", fMemory) {
23 }
24
25 bool CCoinsViewDB::GetCoins(uint256 txid, CCoins &coins) { 
26     return db.Read(make_pair('c', txid), coins); 
27 }
28
29 bool CCoinsViewDB::SetCoins(uint256 txid, const CCoins &coins) {
30     CLevelDBBatch batch;
31     BatchWriteCoins(batch, txid, coins);
32     return db.WriteBatch(batch);
33 }
34
35 bool CCoinsViewDB::HaveCoins(uint256 txid) {
36     return db.Exists(make_pair('c', txid)); 
37 }
38
39 CBlockIndex *CCoinsViewDB::GetBestBlock() {
40     uint256 hashBestChain;
41     if (!db.Read('B', hashBestChain))
42         return NULL;
43     std::map<uint256, CBlockIndex*>::iterator it = mapBlockIndex.find(hashBestChain);
44     if (it == mapBlockIndex.end())
45         return NULL;
46     return it->second;
47 }
48
49 bool CCoinsViewDB::SetBestBlock(CBlockIndex *pindex) {
50     CLevelDBBatch batch;
51     BatchWriteHashBestChain(batch, pindex->GetBlockHash()); 
52     return db.WriteBatch(batch);
53 }
54
55 bool CCoinsViewDB::BatchWrite(const std::map<uint256, CCoins> &mapCoins, CBlockIndex *pindex) {
56     printf("Committing %u changed transactions to coin database...\n", (unsigned int)mapCoins.size());
57
58     CLevelDBBatch batch;
59     for (std::map<uint256, CCoins>::const_iterator it = mapCoins.begin(); it != mapCoins.end(); it++)
60         BatchWriteCoins(batch, it->first, it->second);
61     BatchWriteHashBestChain(batch, pindex->GetBlockHash());
62
63     return db.WriteBatch(batch);
64 }
65
66 CBlockTreeDB::CBlockTreeDB(bool fMemory) : CLevelDB(GetDataDir() / "blktree", fMemory) {
67 }
68
69 bool CBlockTreeDB::WriteBlockIndex(const CDiskBlockIndex& blockindex)
70 {
71     return Write(make_pair('b', blockindex.GetBlockHash()), blockindex);
72 }
73
74 bool CBlockTreeDB::ReadBestInvalidTrust(CBigNum& bnBestInvalidTrust)
75 {
76     return Read('I', bnBestInvalidTrust);
77 }
78
79 bool CBlockTreeDB::WriteBestInvalidTrust(CBigNum bnBestInvalidTrust)
80 {
81     return Write('I', bnBestInvalidTrust);
82 }
83
84 bool CBlockTreeDB::ReadSyncCheckpoint(uint256& hashCheckpoint)
85 {
86     return Read('H', hashCheckpoint);
87 }
88
89 bool CBlockTreeDB::WriteSyncCheckpoint(uint256 hashCheckpoint)
90 {
91     return Write('H', hashCheckpoint);
92 }
93
94 bool CBlockTreeDB::ReadCheckpointPubKey(string& strPubKey)
95 {
96     return Read('K', strPubKey);
97 }
98
99 bool CBlockTreeDB::WriteCheckpointPubKey(const string& strPubKey)
100 {
101     return Write('K', strPubKey);
102 }
103
104 bool CBlockTreeDB::WriteBlockFileInfo(int nFile, const CBlockFileInfo &info) {
105     return Write(make_pair('f', nFile), info);
106 }
107
108 bool CBlockTreeDB::ReadBlockFileInfo(int nFile, CBlockFileInfo &info) {
109     return Read(make_pair('f', nFile), info);
110 }
111
112 bool CBlockTreeDB::WriteLastBlockFile(int nFile) {
113     return Write('l', nFile);
114 }
115
116 bool CBlockTreeDB::ReadLastBlockFile(int &nFile) {
117     return Read('l', nFile);
118 }
119
120 bool CCoinsViewDB::GetStats(CCoinsStats &stats) {
121     leveldb::Iterator *pcursor = db.NewIterator();
122     pcursor->SeekToFirst();
123
124     while (pcursor->Valid()) {
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' && !fRequestShutdown) {
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
138                 stats.nTransactions++;
139                 BOOST_FOREACH(const CTxOut &out, coins.vout) {
140                     if (!out.IsNull())
141                         stats.nTransactionOutputs++;
142                 }
143                 stats.nSerializedSize += 32 + slValue.size();
144             }
145             pcursor->Next();
146         } catch (std::exception &e) {
147             return error("%s() : deserialize error", __PRETTY_FUNCTION__);
148         }
149     }
150     delete pcursor;
151     stats.nHeight = GetBestBlock()->nHeight;
152     return true;
153 }
154
155 bool CBlockTreeDB::LoadBlockIndexGuts()
156 {
157     leveldb::Iterator *pcursor = NewIterator();
158
159     CDataStream ssKeySet(SER_DISK, CLIENT_VERSION);
160     ssKeySet << make_pair('b', uint256(0));
161     pcursor->Seek(ssKeySet.str());
162
163     // Load mapBlockIndex
164     while (pcursor->Valid()) {
165         try {
166             leveldb::Slice slKey = pcursor->key();
167             CDataStream ssKey(slKey.data(), slKey.data()+slKey.size(), SER_DISK, CLIENT_VERSION);
168             char chType;
169             ssKey >> chType;
170             if (chType == 'b' && !fRequestShutdown) {
171                 leveldb::Slice slValue = pcursor->value();
172                 CDataStream ssValue(slValue.data(), slValue.data()+slValue.size(), SER_DISK, CLIENT_VERSION);
173                 CDiskBlockIndex diskindex;
174                 ssValue >> diskindex;
175
176                 uint256 blockHash = diskindex.GetBlockHash();
177
178                 // Construct block index object
179                 CBlockIndex* pindexNew = InsertBlockIndex(blockHash);
180                 pindexNew->pprev          = InsertBlockIndex(diskindex.hashPrev);
181                 pindexNew->nHeight        = diskindex.nHeight;
182                 pindexNew->nFile          = diskindex.nFile;
183                 pindexNew->nDataPos       = diskindex.nDataPos;
184                 pindexNew->nUndoPos       = diskindex.nUndoPos;
185                 pindexNew->nMint          = diskindex.nMint;
186                 pindexNew->nMoneySupply   = diskindex.nMoneySupply;
187                 pindexNew->nFlags         = diskindex.nFlags;
188                 pindexNew->nStakeModifier = diskindex.nStakeModifier;
189                 pindexNew->prevoutStake   = diskindex.prevoutStake;
190                 pindexNew->nStakeTime     = diskindex.nStakeTime;
191                 pindexNew->hashProofOfStake = diskindex.hashProofOfStake;
192                 pindexNew->nVersion       = diskindex.nVersion;
193                 pindexNew->hashMerkleRoot = diskindex.hashMerkleRoot;
194                 pindexNew->nTime          = diskindex.nTime;
195                 pindexNew->nBits          = diskindex.nBits;
196                 pindexNew->nNonce         = diskindex.nNonce;
197                 pindexNew->nStatus        = diskindex.nStatus;
198                 pindexNew->nTx            = diskindex.nTx;
199
200                 // Watch for genesis block
201                 if (pindexGenesisBlock == NULL && blockHash == (!fTestNet ? hashGenesisBlock : hashGenesisBlockTestNet))
202                     pindexGenesisBlock = pindexNew;
203
204                 if (!pindexNew->CheckIndex())
205                     return error("LoadBlockIndex() : CheckIndex failed: %s", pindexNew->ToString().c_str());
206
207                 // Build setStakeSeen
208                 if (pindexNew->IsProofOfStake())
209                     setStakeSeen.insert(make_pair(pindexNew->prevoutStake, pindexNew->nStakeTime));
210
211                 pcursor->Next();
212             } else {
213                 break; // if shutdown requested or finished loading block index
214             }
215         } catch (std::exception &e) {
216             return error("%s() : deserialize error", __PRETTY_FUNCTION__);
217         }
218     }
219     delete pcursor;
220
221     return true;
222 }