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