Make sure that new stake modifier meets fixed generation interval.
[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::ReadModifierUpgradeTime(unsigned int& nUpgradeTime)
102 {
103     return Read('M', nUpgradeTime);
104 }
105
106 bool CBlockTreeDB::WriteModifierUpgradeTime(const unsigned int& nUpgradeTime)
107 {
108     return Write('M', nUpgradeTime);
109 }
110
111 bool CBlockTreeDB::WriteBlockFileInfo(int nFile, const CBlockFileInfo &info) {
112     return Write(make_pair('f', nFile), info);
113 }
114
115 bool CBlockTreeDB::ReadBlockFileInfo(int nFile, CBlockFileInfo &info) {
116     return Read(make_pair('f', nFile), info);
117 }
118
119 bool CBlockTreeDB::WriteLastBlockFile(int nFile) {
120     return Write('l', nFile);
121 }
122
123 bool CBlockTreeDB::ReadLastBlockFile(int &nFile) {
124     return Read('l', nFile);
125 }
126
127 bool CCoinsViewDB::GetStats(CCoinsStats &stats) {
128     leveldb::Iterator *pcursor = db.NewIterator();
129     pcursor->SeekToFirst();
130
131     while (pcursor->Valid()) {
132         try {
133             leveldb::Slice slKey = pcursor->key();
134             CDataStream ssKey(slKey.data(), slKey.data()+slKey.size(), SER_DISK, CLIENT_VERSION);
135             char chType;
136             ssKey >> chType;
137             if (chType == 'c' && !fRequestShutdown) {
138                 leveldb::Slice slValue = pcursor->value();
139                 CDataStream ssValue(slValue.data(), slValue.data()+slValue.size(), SER_DISK, CLIENT_VERSION);
140                 CCoins coins;
141                 ssValue >> coins;
142                 uint256 txhash;
143                 ssKey >> txhash;
144                 if (!coins.IsPruned()) {
145                     stats.nTransactions++;
146                     BOOST_FOREACH(const CTxOut &out, coins.vout) {
147                         if (!out.IsNull())
148                             stats.nTransactionOutputs++;
149                     }
150                 }
151                 else {
152                     stats.nPrunedTransactions++;
153                 }
154                 stats.nSerializedSize += 32 + slValue.size();
155             }
156             pcursor->Next();
157         } catch (std::exception &e) {
158             return error("%s() : deserialize error", __PRETTY_FUNCTION__);
159         }
160     }
161     delete pcursor;
162     stats.nHeight = GetBestBlock()->nHeight;
163     return true;
164 }
165
166 bool CBlockTreeDB::LoadBlockIndexGuts()
167 {
168     leveldb::Iterator *pcursor = NewIterator();
169
170     CDataStream ssKeySet(SER_DISK, CLIENT_VERSION);
171     ssKeySet << make_pair('b', uint256(0));
172     pcursor->Seek(ssKeySet.str());
173
174     // Load mapBlockIndex
175     while (pcursor->Valid()) {
176         try {
177             leveldb::Slice slKey = pcursor->key();
178             CDataStream ssKey(slKey.data(), slKey.data()+slKey.size(), SER_DISK, CLIENT_VERSION);
179             char chType;
180             ssKey >> chType;
181             if (chType == 'b' && !fRequestShutdown) {
182                 leveldb::Slice slValue = pcursor->value();
183                 CDataStream ssValue(slValue.data(), slValue.data()+slValue.size(), SER_DISK, CLIENT_VERSION);
184                 CDiskBlockIndex diskindex;
185                 ssValue >> diskindex;
186
187                 uint256 blockHash = diskindex.GetBlockHash();
188
189                 // Construct block index object
190                 CBlockIndex* pindexNew = InsertBlockIndex(blockHash);
191                 pindexNew->pprev          = InsertBlockIndex(diskindex.hashPrev);
192                 pindexNew->nHeight        = diskindex.nHeight;
193                 pindexNew->nFile          = diskindex.nFile;
194                 pindexNew->nDataPos       = diskindex.nDataPos;
195                 pindexNew->nUndoPos       = diskindex.nUndoPos;
196                 pindexNew->nMint          = diskindex.nMint;
197                 pindexNew->nMoneySupply   = diskindex.nMoneySupply;
198                 pindexNew->nFlags         = diskindex.nFlags;
199                 pindexNew->nStakeModifier = diskindex.nStakeModifier;
200                 pindexNew->prevoutStake   = diskindex.prevoutStake;
201                 pindexNew->nStakeTime     = diskindex.nStakeTime;
202                 pindexNew->hashProofOfStake = diskindex.hashProofOfStake;
203                 pindexNew->nVersion       = diskindex.nVersion;
204                 pindexNew->hashMerkleRoot = diskindex.hashMerkleRoot;
205                 pindexNew->nTime          = diskindex.nTime;
206                 pindexNew->nBits          = diskindex.nBits;
207                 pindexNew->nNonce         = diskindex.nNonce;
208                 pindexNew->nStatus        = diskindex.nStatus;
209                 pindexNew->nTx            = diskindex.nTx;
210
211                 // Watch for genesis block
212                 if (pindexGenesisBlock == NULL && blockHash == (!fTestNet ? hashGenesisBlock : hashGenesisBlockTestNet))
213                     pindexGenesisBlock = pindexNew;
214
215                 if (!pindexNew->CheckIndex())
216                     return error("LoadBlockIndex() : CheckIndex failed: %s", pindexNew->ToString().c_str());
217
218                 // Build setStakeSeen
219                 if (pindexNew->IsProofOfStake())
220                     setStakeSeen.insert(make_pair(pindexNew->prevoutStake, pindexNew->nStakeTime));
221
222                 pcursor->Next();
223             } else {
224                 break; // if shutdown requested or finished loading block index
225             }
226         } catch (std::exception &e) {
227             return error("%s() : deserialize error", __PRETTY_FUNCTION__);
228         }
229     }
230     delete pcursor;
231
232     return true;
233 }