41883d05575f659387ab35d48fca6586001a60f0
[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 CBlockIndex static * InsertBlockIndex(uint256 hash)
143 {
144     if (hash == 0)
145         return NULL;
146
147     // Return existing
148     map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hash);
149     if (mi != mapBlockIndex.end())
150         return (*mi).second;
151
152     // Create new
153     CBlockIndex* pindexNew = new CBlockIndex();
154     if (!pindexNew)
155         throw runtime_error("LoadBlockIndex() : new CBlockIndex failed");
156     mi = mapBlockIndex.insert(make_pair(hash, pindexNew)).first;
157     pindexNew->phashBlock = &((*mi).first);
158
159     return pindexNew;
160 }
161
162 bool CTxDB::LoadBlockIndex()
163 {
164     if (!LoadBlockIndexGuts())
165         return false;
166
167     if (fRequestShutdown)
168         return true;
169
170     // Calculate nChainTrust
171     vector<pair<int, CBlockIndex*> > vSortedByHeight;
172     vSortedByHeight.reserve(mapBlockIndex.size());
173     BOOST_FOREACH(const PAIRTYPE(uint256, CBlockIndex*)& item, mapBlockIndex)
174     {
175         CBlockIndex* pindex = item.second;
176         vSortedByHeight.push_back(make_pair(pindex->nHeight, pindex));
177     }
178     sort(vSortedByHeight.begin(), vSortedByHeight.end());
179     BOOST_FOREACH(const PAIRTYPE(int, CBlockIndex*)& item, vSortedByHeight)
180     {
181         CBlockIndex* pindex = item.second;
182         pindex->nChainTrust = (pindex->pprev ? pindex->pprev->nChainTrust : 0) + pindex->GetBlockTrust();
183         // ppcoin: calculate stake modifier checksum
184         pindex->nStakeModifierChecksum = GetStakeModifierChecksum(pindex);
185         if (!CheckStakeModifierCheckpoints(pindex->nHeight, pindex->nStakeModifierChecksum))
186             return error("CTxDB::LoadBlockIndex() : Failed stake modifier checkpoint height=%d, modifier=0x%016"PRI64x, pindex->nHeight, pindex->nStakeModifier);
187     }
188
189     // Load hashBestChain pointer to end of best chain
190     if (!ReadHashBestChain(hashBestChain))
191     {
192         if (pindexGenesisBlock == NULL)
193             return true;
194         return error("CTxDB::LoadBlockIndex() : hashBestChain not loaded");
195     }
196     if (!mapBlockIndex.count(hashBestChain))
197         return error("CTxDB::LoadBlockIndex() : hashBestChain not found in the block index");
198     pindexBest = mapBlockIndex[hashBestChain];
199     nBestHeight = pindexBest->nHeight;
200     nBestChainTrust = pindexBest->nChainTrust;
201     printf("LoadBlockIndex(): hashBestChain=%s  height=%d  trust=%s  date=%s\n",
202       hashBestChain.ToString().substr(0,20).c_str(), nBestHeight, CBigNum(nBestChainTrust).ToString().c_str(),
203       DateTimeStrFormat("%x %H:%M:%S", pindexBest->GetBlockTime()).c_str());
204
205     // ppcoin: load hashSyncCheckpoint
206     if (!ReadSyncCheckpoint(Checkpoints::hashSyncCheckpoint))
207         return error("CTxDB::LoadBlockIndex() : hashSyncCheckpoint not loaded");
208     printf("LoadBlockIndex(): synchronized checkpoint %s\n", Checkpoints::hashSyncCheckpoint.ToString().c_str());
209
210     // Load bnBestInvalidTrust, OK if it doesn't exist
211     CBigNum bnBestInvalidTrust;
212     ReadBestInvalidTrust(bnBestInvalidTrust);
213     nBestInvalidTrust = bnBestInvalidTrust.getuint256();
214
215     // Verify blocks in the best chain
216     int nCheckLevel = GetArg("-checklevel", 1);
217     int nCheckDepth = GetArg( "-checkblocks", 2500);
218     if (nCheckDepth == 0)
219         nCheckDepth = 1000000000; // suffices until the year 19000
220     if (nCheckDepth > nBestHeight)
221         nCheckDepth = nBestHeight;
222     printf("Verifying last %i blocks at level %i\n", nCheckDepth, nCheckLevel);
223     CBlockIndex* pindexFork = NULL;
224     map<pair<unsigned int, unsigned int>, CBlockIndex*> mapBlockPos;
225     for (CBlockIndex* pindex = pindexBest; pindex && pindex->pprev; pindex = pindex->pprev)
226     {
227         if (fRequestShutdown || pindex->nHeight < nBestHeight-nCheckDepth)
228             break;
229         CBlock block;
230         if (!block.ReadFromDisk(pindex))
231             return error("LoadBlockIndex() : block.ReadFromDisk failed");
232         // check level 1: verify block validity
233         // check level 7: verify block signature too
234         if (nCheckLevel>0 && !block.CheckBlock(true, true, (nCheckLevel>6)))
235         {
236             printf("LoadBlockIndex() : *** found bad block at %d, hash=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString().c_str());
237             pindexFork = pindex->pprev;
238         }
239         // check level 2: verify transaction index validity
240         if (nCheckLevel>1)
241         {
242             pair<unsigned int, unsigned int> pos = make_pair(pindex->nFile, pindex->nBlockPos);
243             mapBlockPos[pos] = pindex;
244             BOOST_FOREACH(const CTransaction &tx, block.vtx)
245             {
246                 uint256 hashTx = tx.GetHash();
247                 CTxIndex txindex;
248                 if (ReadTxIndex(hashTx, txindex))
249                 {
250                     // check level 3: checker transaction hashes
251                     if (nCheckLevel>2 || pindex->nFile != txindex.pos.nFile || pindex->nBlockPos != txindex.pos.nBlockPos)
252                     {
253                         // either an error or a duplicate transaction
254                         CTransaction txFound;
255                         if (!txFound.ReadFromDisk(txindex.pos))
256                         {
257                             printf("LoadBlockIndex() : *** cannot read mislocated transaction %s\n", hashTx.ToString().c_str());
258                             pindexFork = pindex->pprev;
259                         }
260                         else
261                             if (txFound.GetHash() != hashTx) // not a duplicate tx
262                             {
263                                 printf("LoadBlockIndex(): *** invalid tx position for %s\n", hashTx.ToString().c_str());
264                                 pindexFork = pindex->pprev;
265                             }
266                     }
267                     // check level 4: check whether spent txouts were spent within the main chain
268                     unsigned int nOutput = 0;
269                     if (nCheckLevel>3)
270                     {
271                         BOOST_FOREACH(const CDiskTxPos &txpos, txindex.vSpent)
272                         {
273                             if (!txpos.IsNull())
274                             {
275                                 pair<unsigned int, unsigned int> posFind = make_pair(txpos.nFile, txpos.nBlockPos);
276                                 if (!mapBlockPos.count(posFind))
277                                 {
278                                     printf("LoadBlockIndex(): *** found bad spend at %d, hashBlock=%s, hashTx=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString().c_str(), hashTx.ToString().c_str());
279                                     pindexFork = pindex->pprev;
280                                 }
281                                 // check level 6: check whether spent txouts were spent by a valid transaction that consume them
282                                 if (nCheckLevel>5)
283                                 {
284                                     CTransaction txSpend;
285                                     if (!txSpend.ReadFromDisk(txpos))
286                                     {
287                                         printf("LoadBlockIndex(): *** cannot read spending transaction of %s:%i from disk\n", hashTx.ToString().c_str(), nOutput);
288                                         pindexFork = pindex->pprev;
289                                     }
290                                     else if (!txSpend.CheckTransaction())
291                                     {
292                                         printf("LoadBlockIndex(): *** spending transaction of %s:%i is invalid\n", hashTx.ToString().c_str(), nOutput);
293                                         pindexFork = pindex->pprev;
294                                     }
295                                     else
296                                     {
297                                         bool fFound = false;
298                                         BOOST_FOREACH(const CTxIn &txin, txSpend.vin)
299                                             if (txin.prevout.hash == hashTx && txin.prevout.n == nOutput)
300                                                 fFound = true;
301                                         if (!fFound)
302                                         {
303                                             printf("LoadBlockIndex(): *** spending transaction of %s:%i does not spend it\n", hashTx.ToString().c_str(), nOutput);
304                                             pindexFork = pindex->pprev;
305                                         }
306                                     }
307                                 }
308                             }
309                             nOutput++;
310                         }
311                     }
312                 }
313                 // check level 5: check whether all prevouts are marked spent
314                 if (nCheckLevel>4)
315                 {
316                      BOOST_FOREACH(const CTxIn &txin, tx.vin)
317                      {
318                           CTxIndex txindex;
319                           if (ReadTxIndex(txin.prevout.hash, txindex))
320                               if (txindex.vSpent.size()-1 < txin.prevout.n || txindex.vSpent[txin.prevout.n].IsNull())
321                               {
322                                   printf("LoadBlockIndex(): *** found unspent prevout %s:%i in %s\n", txin.prevout.hash.ToString().c_str(), txin.prevout.n, hashTx.ToString().c_str());
323                                   pindexFork = pindex->pprev;
324                               }
325                      }
326                 }
327             }
328         }
329     }
330     if (pindexFork && !fRequestShutdown)
331     {
332         // Reorg back to the fork
333         printf("LoadBlockIndex() : *** moving best chain pointer back to block %d\n", pindexFork->nHeight);
334         CBlock block;
335         if (!block.ReadFromDisk(pindexFork))
336             return error("LoadBlockIndex() : block.ReadFromDisk failed");
337         CTxDB txdb;
338         block.SetBestChain(txdb, pindexFork);
339     }
340
341     return true;
342 }
343
344
345
346 bool CTxDB::LoadBlockIndexGuts()
347 {
348     // Get database cursor
349     Dbc* pcursor = GetCursor();
350     if (!pcursor)
351         return false;
352
353     // Load mapBlockIndex
354     unsigned int fFlags = DB_SET_RANGE;
355     while (true)
356     {
357         // Read next record
358         CDataStream ssKey(SER_DISK, CLIENT_VERSION);
359         if (fFlags == DB_SET_RANGE)
360             ssKey << make_pair(string("blockindex"), uint256(0));
361         CDataStream ssValue(SER_DISK, CLIENT_VERSION);
362         int ret = ReadAtCursor(pcursor, ssKey, ssValue, fFlags);
363         fFlags = DB_NEXT;
364         if (ret == DB_NOTFOUND)
365             break;
366         else if (ret != 0)
367             return false;
368
369         // Unserialize
370
371         try {
372         string strType;
373         ssKey >> strType;
374         if (strType == "blockindex" && !fRequestShutdown)
375         {
376             CDiskBlockIndex diskindex;
377             ssValue >> diskindex;
378
379             // Construct block index object
380             CBlockIndex* pindexNew = InsertBlockIndex(diskindex.GetBlockHash());
381             pindexNew->pprev          = InsertBlockIndex(diskindex.hashPrev);
382             pindexNew->pnext          = InsertBlockIndex(diskindex.hashNext);
383             pindexNew->nFile          = diskindex.nFile;
384             pindexNew->nBlockPos      = diskindex.nBlockPos;
385             pindexNew->nHeight        = diskindex.nHeight;
386             pindexNew->nMint          = diskindex.nMint;
387             pindexNew->nMoneySupply   = diskindex.nMoneySupply;
388             pindexNew->nFlags         = diskindex.nFlags;
389             pindexNew->nStakeModifier = diskindex.nStakeModifier;
390             pindexNew->prevoutStake   = diskindex.prevoutStake;
391             pindexNew->nStakeTime     = diskindex.nStakeTime;
392             pindexNew->hashProofOfStake = diskindex.hashProofOfStake;
393             pindexNew->nVersion       = diskindex.nVersion;
394             pindexNew->hashMerkleRoot = diskindex.hashMerkleRoot;
395             pindexNew->nTime          = diskindex.nTime;
396             pindexNew->nBits          = diskindex.nBits;
397             pindexNew->nNonce         = diskindex.nNonce;
398
399             // Watch for genesis block
400             if (pindexGenesisBlock == NULL && diskindex.GetBlockHash() == (!fTestNet ? hashGenesisBlock : hashGenesisBlockTestNet))
401                 pindexGenesisBlock = pindexNew;
402
403             if (!pindexNew->CheckIndex())
404                 return error("LoadBlockIndex() : CheckIndex failed at %d", pindexNew->nHeight);
405
406             // ppcoin: build setStakeSeen
407             if (pindexNew->IsProofOfStake())
408                 setStakeSeen.insert(make_pair(pindexNew->prevoutStake, pindexNew->nStakeTime));
409         }
410         else
411         {
412             break; // if shutdown requested or finished loading block index
413         }
414         }    // try
415         catch (std::exception &e) {
416             return error("%s() : deserialize error", __PRETTY_FUNCTION__);
417         }
418     }
419     pcursor->close();
420
421     return true;
422 }
423
424