Merge pull request #361 from svost/master
[novacoin.git] / src / txdb-bdb.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 "db.h"
7 #include "kernel.h"
8 #include "checkpoints.h"
9 #include "txdb-bdb.h"
10 #include "util.h"
11 #include "main.h"
12 #include <boost/version.hpp>
13 #include <boost/filesystem.hpp>
14 #include <boost/filesystem/fstream.hpp>
15
16 #ifndef WIN32
17 #include "sys/stat.h"
18 #endif
19
20 using namespace std;
21 using namespace boost;
22
23 void MakeMockTXDB() {
24     // In practice this won't do anything because the test framework always initializes
25     // an in-memory BDB via bitdb.MakeMock() first, as we use BDB for addresses and wallets.
26     if (!bitdb.IsMock())
27         bitdb.MakeMock();
28 }
29
30 //
31 // CTxDB
32 //
33
34 bool CTxDB::ReadTxIndex(uint256 hash, CTxIndex& txindex)
35 {
36     assert(!fClient);
37     txindex.SetNull();
38     return Read(make_pair(string("tx"), hash), txindex);
39 }
40
41 bool CTxDB::UpdateTxIndex(uint256 hash, const CTxIndex& txindex)
42 {
43     assert(!fClient);
44     return Write(make_pair(string("tx"), hash), txindex);
45 }
46
47 bool CTxDB::AddTxIndex(const CTransaction& tx, const CDiskTxPos& pos, int nHeight)
48 {
49     assert(!fClient);
50
51     // Add to tx index
52     uint256 hash = tx.GetHash();
53     CTxIndex txindex(pos, tx.vout.size());
54     return Write(make_pair(string("tx"), hash), txindex);
55 }
56
57 bool CTxDB::EraseTxIndex(const CTransaction& tx)
58 {
59     assert(!fClient);
60     uint256 hash = tx.GetHash();
61
62     return Erase(make_pair(string("tx"), hash));
63 }
64
65 bool CTxDB::ContainsTx(uint256 hash)
66 {
67     assert(!fClient);
68     return Exists(make_pair(string("tx"), hash));
69 }
70
71 bool CTxDB::ReadDiskTx(uint256 hash, CTransaction& tx, CTxIndex& txindex)
72 {
73     assert(!fClient);
74     tx.SetNull();
75     if (!ReadTxIndex(hash, txindex))
76         return false;
77     return (tx.ReadFromDisk(txindex.pos));
78 }
79
80 bool CTxDB::ReadDiskTx(uint256 hash, CTransaction& tx)
81 {
82     CTxIndex txindex;
83     return ReadDiskTx(hash, tx, txindex);
84 }
85
86 bool CTxDB::ReadDiskTx(COutPoint outpoint, CTransaction& tx, CTxIndex& txindex)
87 {
88     return ReadDiskTx(outpoint.hash, tx, txindex);
89 }
90
91 bool CTxDB::ReadDiskTx(COutPoint outpoint, CTransaction& tx)
92 {
93     CTxIndex txindex;
94     return ReadDiskTx(outpoint.hash, tx, txindex);
95 }
96
97 bool CTxDB::WriteBlockIndex(const CDiskBlockIndex& blockindex)
98 {
99     return Write(make_pair(string("blockindex"), blockindex.GetBlockHash()), blockindex);
100 }
101
102 bool CTxDB::ReadHashBestChain(uint256& hashBestChain)
103 {
104     return Read(string("hashBestChain"), hashBestChain);
105 }
106
107 bool CTxDB::WriteHashBestChain(uint256 hashBestChain)
108 {
109     return Write(string("hashBestChain"), hashBestChain);
110 }
111
112 bool CTxDB::ReadBestInvalidTrust(CBigNum& bnBestInvalidTrust)
113 {
114     return Read(string("bnBestInvalidTrust"), bnBestInvalidTrust);
115 }
116
117 bool CTxDB::WriteBestInvalidTrust(CBigNum bnBestInvalidTrust)
118 {
119     return Write(string("bnBestInvalidTrust"), bnBestInvalidTrust);
120 }
121
122 bool CTxDB::ReadSyncCheckpoint(uint256& hashCheckpoint)
123 {
124     return Read(string("hashSyncCheckpoint"), hashCheckpoint);
125 }
126
127 bool CTxDB::WriteSyncCheckpoint(uint256 hashCheckpoint)
128 {
129     return Write(string("hashSyncCheckpoint"), hashCheckpoint);
130 }
131
132 bool CTxDB::ReadCheckpointPubKey(string& strPubKey)
133 {
134     return Read(string("strCheckpointPubKey"), strPubKey);
135 }
136
137 bool CTxDB::WriteCheckpointPubKey(const string& strPubKey)
138 {
139     return Write(string("strCheckpointPubKey"), strPubKey);
140 }
141
142 bool CTxDB::ReadModifierUpgradeTime(unsigned int& nUpgradeTime)
143 {
144     return Read(string("nUpgradeTime"), nUpgradeTime);
145 }
146
147 bool CTxDB::WriteModifierUpgradeTime(const unsigned int& nUpgradeTime)
148 {
149     return Write(string("nUpgradeTime"), nUpgradeTime);
150 }
151
152 CBlockIndex static * InsertBlockIndex(uint256 hash)
153 {
154     if (hash == 0)
155         return NULL;
156
157     // Return existing
158     map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hash);
159     if (mi != mapBlockIndex.end())
160         return (*mi).second;
161
162     // Create new
163     CBlockIndex* pindexNew = new(nothrow) CBlockIndex();
164     if (!pindexNew)
165         throw runtime_error("LoadBlockIndex() : new CBlockIndex failed");
166     mi = mapBlockIndex.insert(make_pair(hash, pindexNew)).first;
167     pindexNew->phashBlock = &((*mi).first);
168
169     return pindexNew;
170 }
171
172 bool CTxDB::LoadBlockIndex()
173 {
174     if (!LoadBlockIndexGuts())
175         return false;
176
177     if (fRequestShutdown)
178         return true;
179
180     // Calculate nChainTrust
181     vector<pair<int, CBlockIndex*> > vSortedByHeight;
182     vSortedByHeight.reserve(mapBlockIndex.size());
183     BOOST_FOREACH(const PAIRTYPE(uint256, CBlockIndex*)& item, mapBlockIndex)
184     {
185         CBlockIndex* pindex = item.second;
186         vSortedByHeight.push_back(make_pair(pindex->nHeight, pindex));
187     }
188     sort(vSortedByHeight.begin(), vSortedByHeight.end());
189     BOOST_FOREACH(const PAIRTYPE(int, CBlockIndex*)& item, vSortedByHeight)
190     {
191         CBlockIndex* pindex = item.second;
192         pindex->nChainTrust = (pindex->pprev ? pindex->pprev->nChainTrust : 0) + pindex->GetBlockTrust();
193         // ppcoin: calculate stake modifier checksum
194         pindex->nStakeModifierChecksum = GetStakeModifierChecksum(pindex);
195         if (!CheckStakeModifierCheckpoints(pindex->nHeight, pindex->nStakeModifierChecksum))
196             return error("CTxDB::LoadBlockIndex() : Failed stake modifier checkpoint height=%d, modifier=0x%016" PRIx64, pindex->nHeight, pindex->nStakeModifier);
197     }
198
199     // Load hashBestChain pointer to end of best chain
200     if (!ReadHashBestChain(hashBestChain))
201     {
202         if (pindexGenesisBlock == NULL)
203             return true;
204         return error("CTxDB::LoadBlockIndex() : hashBestChain not loaded");
205     }
206     if (!mapBlockIndex.count(hashBestChain))
207         return error("CTxDB::LoadBlockIndex() : hashBestChain not found in the block index");
208     pindexBest = mapBlockIndex[hashBestChain];
209     nBestHeight = pindexBest->nHeight;
210     nBestChainTrust = pindexBest->nChainTrust;
211     printf("LoadBlockIndex(): hashBestChain=%s  height=%d  trust=%s  date=%s\n",
212       hashBestChain.ToString().substr(0,20).c_str(), nBestHeight, CBigNum(nBestChainTrust).ToString().c_str(),
213       DateTimeStrFormat("%x %H:%M:%S", pindexBest->GetBlockTime()).c_str());
214
215     // ppcoin: load hashSyncCheckpoint
216     if (!ReadSyncCheckpoint(Checkpoints::hashSyncCheckpoint))
217         return error("CTxDB::LoadBlockIndex() : hashSyncCheckpoint not loaded");
218     printf("LoadBlockIndex(): synchronized checkpoint %s\n", Checkpoints::hashSyncCheckpoint.ToString().c_str());
219
220     // Load bnBestInvalidTrust, OK if it doesn't exist
221     CBigNum bnBestInvalidTrust;
222     ReadBestInvalidTrust(bnBestInvalidTrust);
223     nBestInvalidTrust = bnBestInvalidTrust.getuint256();
224
225     // Verify blocks in the best chain
226     int nCheckLevel = GetArgInt("-checklevel", 1);
227     int nCheckDepth = GetArgInt( "-checkblocks", 2500);
228     if (nCheckDepth == 0)
229         nCheckDepth = 1000000000; // suffices until the year 19000
230     if (nCheckDepth > nBestHeight)
231         nCheckDepth = nBestHeight;
232     printf("Verifying last %i blocks at level %i\n", nCheckDepth, nCheckLevel);
233     CBlockIndex* pindexFork = NULL;
234     map<pair<unsigned int, unsigned int>, CBlockIndex*> mapBlockPos;
235     for (CBlockIndex* pindex = pindexBest; pindex && pindex->pprev; pindex = pindex->pprev)
236     {
237         if (fRequestShutdown || pindex->nHeight < nBestHeight-nCheckDepth)
238             break;
239         CBlock block;
240         if (!block.ReadFromDisk(pindex))
241             return error("LoadBlockIndex() : block.ReadFromDisk failed");
242         // check level 1: verify block validity
243         // check level 7: verify block signature too
244         if (nCheckLevel>0 && !block.CheckBlock(true, true, (nCheckLevel>6)))
245         {
246             printf("LoadBlockIndex() : *** found bad block at %d, hash=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString().c_str());
247             pindexFork = pindex->pprev;
248         }
249         // check level 2: verify transaction index validity
250         if (nCheckLevel>1)
251         {
252             pair<unsigned int, unsigned int> pos = make_pair(pindex->nFile, pindex->nBlockPos);
253             mapBlockPos[pos] = pindex;
254             BOOST_FOREACH(const CTransaction &tx, block.vtx)
255             {
256                 uint256 hashTx = tx.GetHash();
257                 CTxIndex txindex;
258                 if (ReadTxIndex(hashTx, txindex))
259                 {
260                     // check level 3: checker transaction hashes
261                     if (nCheckLevel>2 || pindex->nFile != txindex.pos.nFile || pindex->nBlockPos != txindex.pos.nBlockPos)
262                     {
263                         // either an error or a duplicate transaction
264                         CTransaction txFound;
265                         if (!txFound.ReadFromDisk(txindex.pos))
266                         {
267                             printf("LoadBlockIndex() : *** cannot read mislocated transaction %s\n", hashTx.ToString().c_str());
268                             pindexFork = pindex->pprev;
269                         }
270                         else
271                             if (txFound.GetHash() != hashTx) // not a duplicate tx
272                             {
273                                 printf("LoadBlockIndex(): *** invalid tx position for %s\n", hashTx.ToString().c_str());
274                                 pindexFork = pindex->pprev;
275                             }
276                     }
277                     // check level 4: check whether spent txouts were spent within the main chain
278                     unsigned int nOutput = 0;
279                     if (nCheckLevel>3)
280                     {
281                         BOOST_FOREACH(const CDiskTxPos &txpos, txindex.vSpent)
282                         {
283                             if (!txpos.IsNull())
284                             {
285                                 pair<unsigned int, unsigned int> posFind = make_pair(txpos.nFile, txpos.nBlockPos);
286                                 if (!mapBlockPos.count(posFind))
287                                 {
288                                     printf("LoadBlockIndex(): *** found bad spend at %d, hashBlock=%s, hashTx=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString().c_str(), hashTx.ToString().c_str());
289                                     pindexFork = pindex->pprev;
290                                 }
291                                 // check level 6: check whether spent txouts were spent by a valid transaction that consume them
292                                 if (nCheckLevel>5)
293                                 {
294                                     CTransaction txSpend;
295                                     if (!txSpend.ReadFromDisk(txpos))
296                                     {
297                                         printf("LoadBlockIndex(): *** cannot read spending transaction of %s:%i from disk\n", hashTx.ToString().c_str(), nOutput);
298                                         pindexFork = pindex->pprev;
299                                     }
300                                     else if (!txSpend.CheckTransaction())
301                                     {
302                                         printf("LoadBlockIndex(): *** spending transaction of %s:%i is invalid\n", hashTx.ToString().c_str(), nOutput);
303                                         pindexFork = pindex->pprev;
304                                     }
305                                     else
306                                     {
307                                         bool fFound = false;
308                                         BOOST_FOREACH(const CTxIn &txin, txSpend.vin)
309                                             if (txin.prevout.hash == hashTx && txin.prevout.n == nOutput)
310                                                 fFound = true;
311                                         if (!fFound)
312                                         {
313                                             printf("LoadBlockIndex(): *** spending transaction of %s:%i does not spend it\n", hashTx.ToString().c_str(), nOutput);
314                                             pindexFork = pindex->pprev;
315                                         }
316                                     }
317                                 }
318                             }
319                             nOutput++;
320                         }
321                     }
322                 }
323                 // check level 5: check whether all prevouts are marked spent
324                 if (nCheckLevel>4)
325                 {
326                      BOOST_FOREACH(const CTxIn &txin, tx.vin)
327                      {
328                           CTxIndex txindex;
329                           if (ReadTxIndex(txin.prevout.hash, txindex))
330                               if (txindex.vSpent.size()-1 < txin.prevout.n || txindex.vSpent[txin.prevout.n].IsNull())
331                               {
332                                   printf("LoadBlockIndex(): *** found unspent prevout %s:%i in %s\n", txin.prevout.hash.ToString().c_str(), txin.prevout.n, hashTx.ToString().c_str());
333                                   pindexFork = pindex->pprev;
334                               }
335                      }
336                 }
337             }
338         }
339     }
340     if (pindexFork && !fRequestShutdown)
341     {
342         // Reorg back to the fork
343         printf("LoadBlockIndex() : *** moving best chain pointer back to block %d\n", pindexFork->nHeight);
344         CBlock block;
345         if (!block.ReadFromDisk(pindexFork))
346             return error("LoadBlockIndex() : block.ReadFromDisk failed");
347         CTxDB txdb;
348         block.SetBestChain(txdb, pindexFork);
349     }
350
351     return true;
352 }
353
354
355
356 bool CTxDB::LoadBlockIndexGuts()
357 {
358     // Get database cursor
359     Dbc* pcursor = GetCursor();
360     if (!pcursor)
361         return false;
362
363     // Load mapBlockIndex
364     unsigned int fFlags = DB_SET_RANGE;
365     for ( ; ; )
366     {
367         // Read next record
368         CDataStream ssKey(SER_DISK, CLIENT_VERSION);
369         if (fFlags == DB_SET_RANGE)
370             ssKey << make_pair(string("blockindex"), uint256(0));
371         CDataStream ssValue(SER_DISK, CLIENT_VERSION);
372         int ret = ReadAtCursor(pcursor, ssKey, ssValue, fFlags);
373         fFlags = DB_NEXT;
374         if (ret == DB_NOTFOUND)
375             break;
376         else if (ret != 0)
377             return false;
378
379         // Unserialize
380
381         try {
382         string strType;
383         ssKey >> strType;
384         if (strType == "blockindex" && !fRequestShutdown)
385         {
386             CDiskBlockIndex diskindex;
387             ssValue >> diskindex;
388
389             uint256 blockHash = diskindex.GetBlockHash();
390
391             // Construct block index object
392             CBlockIndex* pindexNew = InsertBlockIndex(blockHash);
393             pindexNew->pprev          = InsertBlockIndex(diskindex.hashPrev);
394             pindexNew->pnext          = InsertBlockIndex(diskindex.hashNext);
395             pindexNew->nFile          = diskindex.nFile;
396             pindexNew->nBlockPos      = diskindex.nBlockPos;
397             pindexNew->nHeight        = diskindex.nHeight;
398             pindexNew->nMint          = diskindex.nMint;
399             pindexNew->nMoneySupply   = diskindex.nMoneySupply;
400             pindexNew->nFlags         = diskindex.nFlags;
401             pindexNew->nStakeModifier = diskindex.nStakeModifier;
402             pindexNew->prevoutStake   = diskindex.prevoutStake;
403             pindexNew->nStakeTime     = diskindex.nStakeTime;
404             pindexNew->hashProofOfStake = diskindex.hashProofOfStake;
405             pindexNew->nVersion       = diskindex.nVersion;
406             pindexNew->hashMerkleRoot = diskindex.hashMerkleRoot;
407             pindexNew->nTime          = diskindex.nTime;
408             pindexNew->nBits          = diskindex.nBits;
409             pindexNew->nNonce         = diskindex.nNonce;
410
411             // Watch for genesis block
412             if (pindexGenesisBlock == NULL && blockHash == (!fTestNet ? hashGenesisBlock : hashGenesisBlockTestNet))
413                 pindexGenesisBlock = pindexNew;
414
415             if (!pindexNew->CheckIndex())
416                 return error("LoadBlockIndex() : CheckIndex failed at %d", pindexNew->nHeight);
417
418             // ppcoin: build setStakeSeen
419             if (pindexNew->IsProofOfStake())
420                 setStakeSeen.insert(make_pair(pindexNew->prevoutStake, pindexNew->nStakeTime));
421         }
422         else
423         {
424             break; // if shutdown requested or finished loading block index
425         }
426         }    // try
427         catch (const std::exception&) {
428             return error("%s() : deserialize error", BOOST_CURRENT_FUNCTION);
429         }
430     }
431     pcursor->close();
432
433     return true;
434 }
435
436